Skip to content

Conversation

@turip
Copy link
Member

@turip turip commented Apr 9, 2025

Overview

This patch changes the plan/subscription/invoicing discount to allow a single discount per type, by changing the discount field of the ratecard to this:

{
   "percentage": {
      "percentage": 10,
   }
  {
    "usage" : 10,
  }
}

Ripple effect on invoicing side

The invoicing actually uses this data to calculate, so the line's ratecard discount have been altered to have the same notion.

The calculated discounts (e.g. how many units we have deducted, how much money we have discounted) on the invoice line remain an array, as there can be multiple amount or unit discounts:

  • If a line has a percentage and a max spend discount multiple amount discounts might be present.

The DiscountReason is still an union type on the LineDiscount, as that's a valid use case-for that: it allows us to correlate which discount/commitment caused the specific invoice line to be created.

DB Changes

This split of unit/amount discounts also necessitated/allowed different db tables for the two. This is beneficial as we can now properly set the null/non null flags.

The remaining field rename and table rename is to be done in a separate PR.

Summary by CodeRabbit

  • New Features

    • Unifies discount handling by distinguishing between usage‑based and amount‑based discounts across billing, invoicing, and subscription modules.
    • Enhances discount data integrity and clarity for improved invoicing and rate card management.
  • Refactoring

    • Streamlines discount validations and error handling.
    • Updates database schema and API definitions to support a more consistent discount representation system.
    • Simplifies discount processing logic by directly accessing discount properties instead of using intermediate methods.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 9, 2025

📝 Walkthrough

Walkthrough

The pull request overhauls discount handling across the API schemas, internal data models, and database structures. Old discount types (e.g., BillingDiscount, InvoiceLineDiscount) have been removed or renamed, and new unified types (e.g., BillingDiscounts, Discounts, BillingInvoiceLineUsageDiscount) have been introduced. In addition, conversion functions, OpenAPI definitions, and specification files have been updated accordingly. Database migration scripts now split and restructure invoice-line discount tables, while test code is modified to access discounts via new fields. A new model type (ManagedModelWithID) has also been added to improve identifier handling.

Changes

File(s) Change Summary
api/client/javascript/src/client/schemas.ts Removed old discount interfaces (BillingDiscount, InvoiceLineDiscount, etc.) and replaced them with unified types (BillingDiscounts, Discounts, InvoiceLineDiscounts, etc.) with updated field descriptions.
api/convert.gen.go Deleted conversions that set the Type fields for discount percentage and usage; now discount conversions omit these assignments.
api/openapi.cloud.yaml and api/openapi.yaml Removed deprecated BillingDiscount and Discount schemas; added new BillingDiscounts, Discounts, and InvoiceLineUsageDiscount schemas with refined properties and descriptive updates.
api/spec/src/** (invoices, productcatalog, ratecards, subscription TSP files) Updated discount types in invoice and productcatalog specifications: removed enums/unions, consolidated multiple discount types into singular, unified structures, renamed fields (e.g., InvoiceDiscountReason→BillingDiscountReason) and transitioned array types to unified objects.
e2e/productcatalog_test.go Changed tests to replace DiscountUsage instances with DiscountPercentage, and updated discount assertions to expect a direct Discounts struct rather than an array.
openmeter/app/stripe/entity/app/invoice.go and files under openmeter/billing/adapter (e.g., invoicelinediff.go, invoicelinediff_test.go, invoicelinemapper.go, invoicelineprogressive.go, invoicelines.go, billing/app.go, discount.go, httpdriver/*) Refactored invoice discount retrieval: replaced method calls with direct field accesses (e.g., iterating over line.Discounts.Amount and .Usage), added new methods for getting discounts by ID, and removed legacy discount-access logic.
openmeter/ent/db/* (all billing invoice discount related files) Removed the old BillingInvoiceDiscount files; added new files and update logic for BillingInvoiceLineUsageDiscount and split line discounts into amount and usage discounts. Schema, client, query, and migration definitions have been extensively revised.
openmeter/productcatalog/discount.go and discount_test.go Removed the Discount type and related DiscountType constants; redefined Discounts as a struct with separate Percentage and Usage pointers, with new validation, cloning, and JSON methods.
openmeter/productcatalog/ratecard.go and ratecard_test.go Updated cloning and validation logic of rate cards by removing unnecessary length checks and enforcing that flat fee rate cards do not include usage discounts.
openmeter/productcatalog/subscription/http/mapping.go and subscription repo/mapping changes Simplified discount mapping by calling FromDiscounts directly and using default empty Discounts instead of nil, along with minor test adjustments.
pkg/models/model.go Added a new type ManagedModelWithID that embeds ManagedModel and includes an ID field with GetID, Equal, and Validate methods.
Test files (e.g., test/app/stripe/invoice_test.go, test/billing/adapter_test.go, test/billing/discount_test.go, test/billing/invoice_test.go) Updated discount assertions and helper functions to reflect the new structure (direct field access instead of indexing into slices) and renamed helper functions (e.g., findDiscountByDescription → findAmountDiscountByDescription).
Migration scripts (tools/migrate/migrations/20250411062903_billing-split-line-discounts.down.sql and .up.sql) In the UP migration, created a new table for billing_invoice_line_usage_discounts with new constraints and indexes, altered billing_invoice_line_discounts, and dropped the legacy billing_invoice_discounts table. The DOWN migration reverses these changes.
Other ent and subscription files (e.g., in openmeter/ent/db/*, openmeter/subscription/repo/*) Updated client instantiations and transaction clients to remove the old BillingInvoiceDiscount client and add the new BillingInvoiceLineUsageDiscount client; adjusted validations and defaulting in subscription item creation and update.
openmeter/productcatalog/addon/ratecard_test.go In test utilities, replaced the factory call for creating a discount with a direct struct pointer assignment for PercentageDiscount.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (1.64.8)

Error: you are using a configuration file for golangci-lint v2 with golangci-lint v1: please use golangci-lint v2
Failed executing command with error: you are using a configuration file for golangci-lint v2 with golangci-lint v1: please use golangci-lint v2

🔧 SQLFluff (3.3.0)
tools/migrate/migrations/20250411062903_billing-split-line-discounts.up.sql

User Error: No dialect was specified. You must configure a dialect or specify one on the command line using --dialect after the command. Available dialects:
ansi, athena, bigquery, clickhouse, databricks, db2, duckdb, exasol, greenplum, hive, impala, mariadb, materialize, mysql, oracle, postgres, redshift, snowflake, soql, sparksql, sqlite, starrocks, teradata, trino, tsql, vertica

tools/migrate/migrations/20250411062903_billing-split-line-discounts.down.sql

User Error: No dialect was specified. You must configure a dialect or specify one on the command line using --dialect after the command. Available dialects:
ansi, athena, bigquery, clickhouse, databricks, db2, duckdb, exasol, greenplum, hive, impala, mariadb, materialize, mysql, oracle, postgres, redshift, snowflake, soql, sparksql, sqlite, starrocks, teradata, trino, tsql, vertica

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@turip turip force-pushed the refactor/allow-single-discount-per-type branch from 58cfc86 to fdcdf3e Compare April 9, 2025 19:01
@turip turip changed the base branch from main to galexi/refactor/remove-subscription-ratecard April 9, 2025 19:02
@turip turip force-pushed the galexi/refactor/remove-subscription-ratecard branch from ec60da3 to 737fe8b Compare April 9, 2025 19:02
@turip turip force-pushed the refactor/allow-single-discount-per-type branch 4 times, most recently from c35b3da to 608047a Compare April 10, 2025 09:38
Base automatically changed from galexi/refactor/remove-subscription-ratecard to main April 10, 2025 09:48
@turip turip force-pushed the refactor/allow-single-discount-per-type branch 3 times, most recently from 3318f3a to 2b03f78 Compare April 10, 2025 20:33
@turip turip added the release-note/breaking-change Release note: Breaking Changes label Apr 10, 2025
@turip turip force-pushed the refactor/allow-single-discount-per-type branch 3 times, most recently from 68f6faa to 85bb524 Compare April 11, 2025 06:42
@turip turip marked this pull request as ready for review April 11, 2025 06:43
@turip turip requested a review from a team as a code owner April 11, 2025 06:43
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: 1

🔭 Outside diff range comments (1)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (1)

1-192: 💡 Verification agent

❓ Verification inconclusive

Missing entity-specific unit tests.
No test code is shown for the newly introduced billinginvoicelineusagediscount entity. Consider adding unit tests (or integration tests) verifying record creation, validations (ReasonValidator), and relationships (EdgeBillingInvoiceLine).

Below is a script to check if tests exist for billinginvoicelineusagediscount in the codebase:


🏁 Script executed:

#!/bin/bash
# Description: Search for tests related to billinginvoicelineusagediscount.

fd billinginvoicelineusagediscount_test | xargs cat

Length of output: 53


Action Required: Add Unit and Integration Tests for the billinginvoicelineusagediscount Entity
The codebase scan did not reveal any tests (e.g., *_test.go files referencing billinginvoicelineusagediscount or related identifiers). To ensure robust coverage, please add tests that verify:

  • Record Creation: Validate default values (e.g., DefaultCreatedAt, DefaultUpdatedAt, etc.) and proper data insertion for the entity.
  • Validations: Confirm that ReasonValidator properly accepts the allowed enum values ("maximum_spend", "ratecard_percentage", "ratecard_usage") and rejects invalid ones.
  • Relationships: Test the handling of the relationship edge (EdgeBillingInvoiceLine) to ensure the entity correctly links with the billing invoice line and related entities.
🧹 Nitpick comments (40)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (1)

87-91: ValidColumn function now handles special fields differently.

The function has been updated to check additional fields that aren't included in the main Columns slice. While functional, this creates an inconsistency in how column validation is handled.

Consider whether these fields should be included directly in the Columns slice for consistency, though I understand this may be constrained by the code generation patterns.

openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (2)

15-72: Check table naming and single discount per type enforcement.
The table name is billing_invoice_line_usage_discounts, implying that multiple records can exist for each line. Since the PR aims to enforce only one discount entry per type, ensure that database constraints or application logic prevent multiple usage-discount records of the same type from being inserted.

Would you like guidance on adding uniqueness constraints in Ent to guarantee only a single usage discount per type and line?


84-95: Add validation for ReasonDetails if applicable.
The ValueScanner includes ReasonDetails but there's currently no validation function for it. If you need to enforce constraints (e.g., max length, allowed characters), consider adding a validator similar to NamespaceValidator.

openmeter/billing/httpdriver/invoiceline.go (1)

428-490: Consider revising the error message for usage discounts.
Inside the usage discount mapping block (lines 462-487), the error at line 483 logs "failed to map amount discounts" instead of "failed to map usage discounts."

- return nil, fmt.Errorf("failed to map amount discounts: %w", err)
+ return nil, fmt.Errorf("failed to map usage discounts: %w", err)
api/openapi.yaml (9)

10585-10606: Improve Correlation ID Description Clarity
The description for the correlation ID field (lines 10588–10600) is quite verbose and contains a grammatical issue (“setups the discount amounts” should be rephrased). Consider simplifying and clarifying this text; for example:

“If not provided, the invoicing engine will auto‐generate one. When editing an invoice line, ensure that the correlation ID remains unchanged to prevent discount amount inaccuracies.”


10624-10644: Standardize Correlation ID Guidance for Usage Discounts
The correlation ID guidance (lines 10627–10629) is very similar to that used elsewhere. To promote consistency and reduce duplication, consider standardizing this wording across discount types.


12179-12203: Enhance Clarity for Ratecard Percentage Discount Details
For the DiscountReasonRatecardPercentage schema, the added correlationId and its detailed description are helpful. However, the text could be simplified and the grammatical error (“setups” should be “setup”) corrected. A revised version might read:

“Correlation ID for the discount. If not provided, the invoicing engine will auto‐generate one. When editing an invoice line, maintain the same correlation ID to ensure accurate discount amounts.”


12209-12234: Review DiscountReasonRatecardUsage Schema Consistency
The DiscountReasonRatecardUsage schema (lines 12209–12234) mirrors the structure of its percentage counterpart. The inclusion of quantity and correlationId is consistent. As with the previous schema, consider refining the long description for clarity and consistency.


14430-14437: Correct Typo in Discounts Description
The description in line 14436 contains a typo ("detailes"). Please correct it to "details" to maintain professionalism.


14810-14852: Review InvoiceLineDiscounts Structure and Terminology
The InvoiceLineDiscounts schema (lines 14810–14852) now features arrays for both amount- and usage-based discounts. The structure is clear; however, review the use of “deduced” in the descriptions to ensure it accurately reflects the business logic—if the intention is to imply “deducted,” that change might be necessary.


14934-15008: Grammar Correction in InvoiceLineUsageDiscount Description
In the InvoiceLineUsageDiscount schema (lines 14934–15008), the description states “represents an usage-based discount.” This should be corrected to “represents a usage-based discount.”


15552-15559: Fix Typo in Repeated Discounts Description
The typo “detailes” appears again in the description (line 15558). Please fix it to “details.”


15837-15844: Minor Rephrase for Usage-Based Rate Card Description
In the InvoiceUsageBasedRateCard schema (lines 15837–15844), change “an usage-based line” to “a usage-based line” to correct the article usage.

openmeter/ent/db/migrate/schema.go (2)

777-783: Rename 'type' field for clarity & ensure references are updated
The newly introduced "type" field here might be ambiguous in the broader context. Consider renaming it to something like "discount_type" to avoid collisions with other "type" fields and to improve clarity. Also ensure that all references in application code and migrations are updated accordingly.

- {Name: "type", Type: field.TypeString, Nullable: true},
+ {Name: "discount_type", Type: field.TypeString, Nullable: true},

826-879: New usage-based discounts table
This new table cleanly separates usage-based discounts from amount-based discounts, aligning with the single discount per type objective. The schema fields appear consistent.
As an optional improvement, consider matching naming conventions (e.g., adding a discount_type field or grouping some fields under one JSON structure) for uniformity with the existing discount table.

api/openapi.cloud.yaml (11)

10759-10778: Clarify Correlation ID Text and BillingDiscountReason Structure.
The updated description for auto-generating a correlation ID is helpful, but the phrase “setups the discount amounts might be incorrect” is unclear. Consider rephrasing it (e.g., “otherwise, the discount amounts might be incorrect”) for better clarity. Additionally, the new BillingDiscountReason schema using a oneOf construct and discriminator is well structured.


10797-10816: Consolidate Discount Types Using BillingDiscounts.
The addition of the BillingDiscounts schema—which encapsulates both percentage and usage discounts—is a clear step toward the single discount per type objective. To improve consistency, consider revising the repeated correlation ID text (especially the unclear “setups” wording) across similar descriptions.


12275-12298: Verify DiscountPercentage and DiscountReasonMaximumSpend Schemas.
The new DiscountPercentage schema effectively constrains the percentage value, and DiscountReasonMaximumSpend is clearly set up with an enum. Ensure that any additional documentation or examples elsewhere in the API clarify their intended usage.


12304-12328: Ensure Clarity in DiscountReasonRatecardPercentage.
The schema for a ratecard percentage discount is well defined with properties for type, percentage, and a correlationId. However, the correlationId’s description repeats the unclear phrasing regarding auto-generation. A clearer wording and a verification of the regex pattern’s correctness are recommended.


12334-12363: Review DiscountReasonRatecardUsage and DiscountUsage Schemas.
The DiscountReasonRatecardUsage schema mirrors the ratecard percentage structure, including a correlationId with similar descriptive text. The subsequent minimal DiscountUsage schema is acceptable; however, double-check that the “quantity” requirement (noting it must be positive) is captured consistently in both documentation and schema constraints.


14362-14369: Fix Typographical Error in Discount Description.
The description reads “Discounts detailes applied to this line.” Please correct “detailes” to “details” for clarity.


14866-14940: Review InvoiceLineUsageDiscount Schema for Completeness.
The InvoiceLineUsageDiscount schema is detailed and includes all necessary fields such as timestamps, IDs, and references to external IDs. Note the grammatical error “an usage-based discount” (should be “a usage-based discount”) and consider revising it. Also, verify that the explanation for preLinePeriodQuantity is unambiguous.


15484-15491: Correct Typo in Discount Details Description.
Similar to an earlier comment, the description “Discounts detailes applied to this line.” contains a typographical error. Please change “detailes” to “details.”


15769-15776: Review InvoiceUsageBasedRateCard Discount Integration.
The InvoiceUsageBasedRateCard schema now includes a discounts property referencing BillingDiscounts. Correct the grammatical error (“an usage-based line” should be “a usage-based line”) and ensure that the discount information is applied consistently with the overall model changes.


17785-17792: Verify Discount Schema Usage in Example Configuration.
In this example configuration, the discounts field now references the Discounts schema (instead of BillingDiscounts). Confirm that this is intentional for flat fee rate cards—especially given the comment that only percentage discounts are supported when the price is set—and that the provided example values (e.g., amount: '100') appropriately reflect real-world usage.


19214-19221: Validate Nested Discount Field within Price Object.
The discounts property within the Price object uses the Discounts schema and is properly titled. To further aid API consumers, consider providing a concrete example (beyond an empty object) if applicable.

openmeter/billing/service/lineservice/discountpercentage.go (1)

54-66: Add brief documentation on CorrelationID usage.
The logic to return an error if CorrelationID is missing is valid. Consider adding a short doc comment explaining "CorrelationID" to maintainers.

openmeter/billing/adapter/invoicelinediff.go (3)

64-72: Typo in type aliases.
Consider renaming "Manged" to "Managed" for clarity and consistency.

-usageLineDiscountMangedWithLine
+usageLineDiscountManagedWithLine

-amountLineDiscountMangedWithLine
+amountLineDiscountManagedWithLine

80-81: Separate diffs for usage and amount discounts.
Storing them individually improves clarity in the single-discount-per-type flow. Just be mindful of the “Managed” spelling in the type aliases.


388-421: Versatile discount handling logic.
Splitting logic by operation (create, delete, update) is straightforward. Consider a default case if new operations arise.

openmeter/ent/schema/billing.go (1)

543-555: Refactoring for the future rename.
There's a TODO about renaming this struct. If a rename is still planned, consider coordinating it with related table/entity names to avoid confusion.

Do you want me to open an issue to track this rename for a subsequent release?

openmeter/ent/db/billinginvoicelinediscount_update.go (5)

128-132: Setter for InvoicingAppExternalID is properly aligned with the typical ent pattern.
Consider whether an additional validation (e.g., length or format) is needed.


194-198: Setter for the 'type' field.
Marked as deprecated; if usage is minimal, consider removing it in a future refactor.


200-206: Nillable setter for deprecated 'type'.
Continues the existing pattern but reevaluate usage of this deprecated field.


391-396: Handles the (deprecated) type field in the SQL update.
Implementation is fine, but consider removing this logic once the field is fully phased out.


845-847: Retrieves 'type' from mutation and sets it in the UpdateOne flow.
Again, watch for usage in future cleanups.

openmeter/ent/db/billinginvoicelineusagediscount_create.go (3)

193-200: Use caution with SaveX in production

SaveX panics on error, which can be disruptive in production if not carefully handled. Consider using Save and returning the error for a more graceful approach.


251-257: Consider enforcing single discount per reason type

The check enforces that reason must be set, but there's no unique constraint on (line_id, reason). To guarantee only one discount per reason type per line, consider adding a unique database constraint in the Ent schema.


817-844: Caution with ID retrieval on MySQL upsert

MySQL doesn't support returning string IDs in upsert scenarios. If you rely on retrieving the ID to continue processing, consider an alternative database or logic path to handle ID lookups after conflict resolution.

openmeter/ent/db/billinginvoicelinediscount_create.go (1)

117-121: Consider adding validation for InvoicingAppExternalID.
If this field has a prescribed format or length limits, a validator would improve data integrity.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f1a051 and 85bb524.

⛔ Files ignored due to path filters (1)
  • tools/migrate/migrations/atlas.sum is excluded by !**/*.sum
📒 Files selected for processing (96)
  • api/client/javascript/src/client/schemas.ts (20 hunks)
  • api/convert.gen.go (0 hunks)
  • api/openapi.cloud.yaml (19 hunks)
  • api/openapi.yaml (20 hunks)
  • api/spec/src/billing/invoices/discounts.tsp (4 hunks)
  • api/spec/src/billing/invoices/invoice.tsp (3 hunks)
  • api/spec/src/productcatalog/discounts.tsp (1 hunks)
  • api/spec/src/productcatalog/ratecards.tsp (2 hunks)
  • api/spec/src/productcatalog/subscription.tsp (2 hunks)
  • e2e/productcatalog_test.go (4 hunks)
  • openmeter/app/stripe/entity/app/invoice.go (2 hunks)
  • openmeter/billing/adapter/invoicelinediff.go (2 hunks)
  • openmeter/billing/adapter/invoicelinediff_test.go (16 hunks)
  • openmeter/billing/adapter/invoicelinemapper.go (2 hunks)
  • openmeter/billing/adapter/invoicelineprogressive.go (2 hunks)
  • openmeter/billing/adapter/invoicelines.go (5 hunks)
  • openmeter/billing/app.go (1 hunks)
  • openmeter/billing/discount.go (4 hunks)
  • openmeter/billing/httpdriver/deprecations.go (2 hunks)
  • openmeter/billing/httpdriver/discounts.go (1 hunks)
  • openmeter/billing/httpdriver/invoiceline.go (1 hunks)
  • openmeter/billing/invoiceline.go (1 hunks)
  • openmeter/billing/invoicelinediscount.go (9 hunks)
  • openmeter/billing/service/discounts.go (1 hunks)
  • openmeter/billing/service/lineservice/discountpercentage.go (3 hunks)
  • openmeter/billing/service/lineservice/feeline.go (3 hunks)
  • openmeter/billing/service/lineservice/feeline_test.go (2 hunks)
  • openmeter/billing/service/lineservice/pricedynamic_test.go (1 hunks)
  • openmeter/billing/service/lineservice/pricegraduatedtiered_test.go (1 hunks)
  • openmeter/billing/service/lineservice/pricepackage_test.go (1 hunks)
  • openmeter/billing/service/lineservice/priceunit_test.go (3 hunks)
  • openmeter/billing/service/lineservice/pricevolumetiered_test.go (1 hunks)
  • openmeter/billing/service/lineservice/usagebasedline.go (2 hunks)
  • openmeter/billing/service/lineservice/usagebasedline_test.go (5 hunks)
  • openmeter/ent/db/addonratecard_create.go (1 hunks)
  • openmeter/ent/db/addonratecard_update.go (2 hunks)
  • openmeter/ent/db/billinginvoicediscount.go (0 hunks)
  • openmeter/ent/db/billinginvoicediscount/billinginvoicediscount.go (0 hunks)
  • openmeter/ent/db/billinginvoicediscount/where.go (0 hunks)
  • openmeter/ent/db/billinginvoicediscount_create.go (0 hunks)
  • openmeter/ent/db/billinginvoicediscount_delete.go (0 hunks)
  • openmeter/ent/db/billinginvoicediscount_query.go (0 hunks)
  • openmeter/ent/db/billinginvoicediscount_update.go (0 hunks)
  • openmeter/ent/db/billinginvoiceline.go (6 hunks)
  • openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (4 hunks)
  • openmeter/ent/db/billinginvoiceline/where.go (1 hunks)
  • openmeter/ent/db/billinginvoiceline_create.go (3 hunks)
  • openmeter/ent/db/billinginvoiceline_query.go (10 hunks)
  • openmeter/ent/db/billinginvoiceline_update.go (9 hunks)
  • openmeter/ent/db/billinginvoicelinediscount.go (5 hunks)
  • openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (6 hunks)
  • openmeter/ent/db/billinginvoicelinediscount/where.go (4 hunks)
  • openmeter/ent/db/billinginvoicelinediscount_create.go (12 hunks)
  • openmeter/ent/db/billinginvoicelinediscount_update.go (8 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount.go (1 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (1 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount/where.go (1 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount_create.go (1 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount_delete.go (1 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount_query.go (1 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount_update.go (1 hunks)
  • openmeter/ent/db/client.go (11 hunks)
  • openmeter/ent/db/ent.go (2 hunks)
  • openmeter/ent/db/expose.go (1 hunks)
  • openmeter/ent/db/hook/hook.go (1 hunks)
  • openmeter/ent/db/migrate/schema.go (5 hunks)
  • openmeter/ent/db/paginate.go (5 hunks)
  • openmeter/ent/db/planratecard_create.go (1 hunks)
  • openmeter/ent/db/planratecard_update.go (2 hunks)
  • openmeter/ent/db/predicate/predicate.go (1 hunks)
  • openmeter/ent/db/runtime.go (2 hunks)
  • openmeter/ent/db/setorclear.go (3 hunks)
  • openmeter/ent/db/subscriptionitem_create.go (1 hunks)
  • openmeter/ent/db/subscriptionitem_update.go (2 hunks)
  • openmeter/ent/db/tx.go (2 hunks)
  • openmeter/ent/schema/billing.go (6 hunks)
  • openmeter/ent/schema/productcatalog.go (0 hunks)
  • openmeter/productcatalog/addon/ratecard_test.go (1 hunks)
  • openmeter/productcatalog/discount.go (3 hunks)
  • openmeter/productcatalog/discount_test.go (3 hunks)
  • openmeter/productcatalog/http/mapping.go (5 hunks)
  • openmeter/productcatalog/plan/ratecard_test.go (1 hunks)
  • openmeter/productcatalog/ratecard.go (4 hunks)
  • openmeter/productcatalog/ratecard_test.go (9 hunks)
  • openmeter/productcatalog/subscription/http/mapping.go (1 hunks)
  • openmeter/productcatalog/subscription/service/plan_test.go (1 hunks)
  • openmeter/subscription/repo/mapping.go (1 hunks)
  • openmeter/subscription/repo/subscriptionitemrepo.go (1 hunks)
  • openmeter/subscription/testutils/ratecard.go (1 hunks)
  • pkg/models/model.go (1 hunks)
  • test/app/stripe/invoice_test.go (1 hunks)
  • test/billing/adapter_test.go (3 hunks)
  • test/billing/discount_test.go (4 hunks)
  • test/billing/invoice_test.go (8 hunks)
  • tools/migrate/migrations/20250411062903_billing-split-line-discounts.down.sql (1 hunks)
  • tools/migrate/migrations/20250411062903_billing-split-line-discounts.up.sql (1 hunks)
💤 Files with no reviewable changes (9)
  • openmeter/ent/schema/productcatalog.go
  • api/convert.gen.go
  • openmeter/ent/db/billinginvoicediscount/where.go
  • openmeter/ent/db/billinginvoicediscount_update.go
  • openmeter/ent/db/billinginvoicediscount_delete.go
  • openmeter/ent/db/billinginvoicediscount_query.go
  • openmeter/ent/db/billinginvoicediscount_create.go
  • openmeter/ent/db/billinginvoicediscount.go
  • openmeter/ent/db/billinginvoicediscount/billinginvoicediscount.go
🧰 Additional context used
🧬 Code Graph Analysis (55)
openmeter/subscription/repo/mapping.go (5)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
api/client/javascript/src/client/schemas.ts (1)
  • Discounts (9386-9386)
api/api.gen.go (1)
  • Discounts (2020-2026)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
api/client/go/client.gen.go (1)
  • Discounts (1891-1897)
openmeter/ent/db/predicate/predicate.go (2)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/ent/schema/billing.go (5)
  • BillingInvoiceLineUsageDiscount (627-629)
  • BillingInvoiceLineUsageDiscount (631-638)
  • BillingInvoiceLineUsageDiscount (640-664)
  • BillingInvoiceLineUsageDiscount (666-675)
  • BillingInvoiceLineUsageDiscount (677-685)
test/app/stripe/invoice_test.go (7)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
api/api.gen.go (1)
  • Discounts (2020-2026)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
api/client/go/client.gen.go (1)
  • Discounts (1891-1897)
openmeter/ent/db/billinginvoiceline/where.go (2)
  • Amount (102-104)
  • Description (97-99)
openmeter/ent/db/billinginvoicelinediscount/where.go (2)
  • Amount (111-113)
  • Description (101-103)
openmeter/ent/db/billinginvoicelineusagediscount/where.go (1)
  • Description (101-103)
openmeter/ent/db/expose.go (4)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/ent/db/predicate/predicate.go (1)
  • BillingInvoiceLineUsageDiscount (93-93)
openmeter/ent/schema/billing.go (5)
  • BillingInvoiceLineUsageDiscount (627-629)
  • BillingInvoiceLineUsageDiscount (631-638)
  • BillingInvoiceLineUsageDiscount (640-664)
  • BillingInvoiceLineUsageDiscount (666-675)
  • BillingInvoiceLineUsageDiscount (677-685)
openmeter/ent/db/client.go (1)
  • NewBillingInvoiceLineUsageDiscountClient (2921-2923)
openmeter/billing/adapter/invoicelineprogressive.go (5)
openmeter/ent/db/billinginvoicelinediscount_query.go (1)
  • BillingInvoiceLineDiscountQuery (21-32)
openmeter/ent/db/billinginvoiceline/where.go (1)
  • DeletedAtIsNil (398-400)
openmeter/ent/db/billinginvoicelinediscount/where.go (1)
  • DeletedAtIsNil (321-323)
openmeter/ent/db/billinginvoicelineusagediscount/where.go (1)
  • DeletedAtIsNil (306-308)
openmeter/ent/db/billinginvoicelineusagediscount_query.go (1)
  • BillingInvoiceLineUsageDiscountQuery (21-32)
openmeter/productcatalog/subscription/http/mapping.go (6)
api/api.gen.go (3)
  • Discounts (2020-2026)
  • SubscriptionItem (5695-5755)
  • RateCard (4980-4982)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
openmeter/productcatalog/http/mapping.go (1)
  • FromDiscounts (320-339)
openmeter/subscription/item.go (1)
  • SubscriptionItem (9-39)
openmeter/ent/db/subscriptionitem.go (2)
  • SubscriptionItem (21-71)
  • SubscriptionItem (129-154)
openmeter/productcatalog/ratecard.go (1)
  • RateCard (27-38)
test/billing/discount_test.go (3)
openmeter/billing/discount.go (3)
  • PercentageDiscount (24-28)
  • Discounts (78-81)
  • UsageDiscount (49-53)
openmeter/productcatalog/discount.go (3)
  • PercentageDiscount (21-24)
  • Discounts (113-116)
  • UsageDiscount (60-62)
openmeter/billing/invoiceline.go (1)
  • Line (279-293)
openmeter/billing/service/lineservice/usagebasedline_test.go (2)
openmeter/billing/discount.go (3)
  • Discounts (78-81)
  • NewDiscountReasonFrom (154-191)
  • MaximumSpendDiscount (145-145)
openmeter/billing/invoicelinediscount.go (4)
  • LineDiscounts (312-315)
  • AmountLineDiscountManaged (104-107)
  • AmountLineDiscount (56-64)
  • LineDiscountBase (22-27)
openmeter/billing/httpdriver/discounts.go (3)
openmeter/productcatalog/http/mapping.go (3)
  • AsDiscounts (523-545)
  • AsPercentageDiscount (558-562)
  • AsUsageDiscount (547-556)
api/api.gen.go (3)
  • BillingDiscounts (1089-1095)
  • Discounts (2020-2026)
  • Percentage (4688-4688)
openmeter/productcatalog/discount.go (3)
  • Discounts (113-116)
  • PercentageDiscount (21-24)
  • UsageDiscount (60-62)
openmeter/ent/db/tx.go (4)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/ent/db/predicate/predicate.go (1)
  • BillingInvoiceLineUsageDiscount (93-93)
openmeter/ent/schema/billing.go (5)
  • BillingInvoiceLineUsageDiscount (627-629)
  • BillingInvoiceLineUsageDiscount (631-638)
  • BillingInvoiceLineUsageDiscount (640-664)
  • BillingInvoiceLineUsageDiscount (666-675)
  • BillingInvoiceLineUsageDiscount (677-685)
openmeter/ent/db/client.go (2)
  • BillingInvoiceLineUsageDiscountClient (2916-2918)
  • NewBillingInvoiceLineUsageDiscountClient (2921-2923)
openmeter/ent/db/runtime.go (1)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (1)
  • ValueScanner (96-98)
openmeter/ent/db/hook/hook.go (2)
openmeter/ent/db/mutation.go (1)
  • BillingInvoiceLineUsageDiscountMutation (18699-18721)
openmeter/ent/db/ent.go (2)
  • Value (64-64)
  • Mutation (75-75)
openmeter/productcatalog/ratecard.go (4)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
api/api.gen.go (1)
  • Discounts (2020-2026)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
api/client/go/client.gen.go (1)
  • Discounts (1891-1897)
openmeter/billing/service/lineservice/feeline_test.go (3)
openmeter/billing/discount.go (2)
  • PercentageDiscount (24-28)
  • Discounts (78-81)
openmeter/productcatalog/discount.go (2)
  • PercentageDiscount (21-24)
  • Discounts (113-116)
openmeter/billing/invoicelinediscount.go (3)
  • LineDiscounts (312-315)
  • AmountLineDiscount (56-64)
  • LineDiscountBase (22-27)
openmeter/ent/db/subscriptionitem_update.go (3)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
api/api.gen.go (1)
  • Discounts (2020-2026)
pkg/models/validator.go (1)
  • Validate (16-26)
openmeter/productcatalog/http/mapping.go (5)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
api/api.gen.go (4)
  • Discounts (2020-2026)
  • DiscountUsage (2012-2017)
  • Percentage (4688-4688)
  • DiscountPercentage (1954-1957)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
api/client/go/client.gen.go (4)
  • Discounts (1891-1897)
  • DiscountUsage (1883-1888)
  • Percentage (4384-4384)
  • DiscountPercentage (1825-1828)
openmeter/billing/httpdriver/discounts.go (3)
  • AsDiscounts (34-64)
  • AsUsageDiscount (20-32)
  • AsPercentageDiscount (13-18)
openmeter/billing/adapter/invoicelinemapper.go (4)
openmeter/billing/discount.go (3)
  • Discounts (78-81)
  • MaximumSpendDiscountReason (131-131)
  • MaximumSpendDiscount (145-145)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/billing/invoicelinediscount.go (3)
  • UsageLineDiscountManaged (254-257)
  • LineDiscountBase (22-27)
  • UsageLineDiscount (205-210)
openmeter/billing/invoiceline.go (1)
  • LineExternalIDs (235-237)
test/billing/adapter_test.go (2)
openmeter/billing/discount.go (4)
  • Discounts (78-81)
  • NewDiscountReasonFrom (154-191)
  • MaximumSpendDiscount (145-145)
  • PercentageDiscount (24-28)
openmeter/billing/invoicelinediscount.go (4)
  • LineDiscounts (312-315)
  • AmountLineDiscountManaged (104-107)
  • AmountLineDiscount (56-64)
  • LineDiscountBase (22-27)
openmeter/billing/service/discounts.go (3)
api/api.gen.go (2)
  • Percentage (4688-4688)
  • Discounts (2020-2026)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
openmeter/productcatalog/ratecard_test.go (2)
pkg/models/percentage.go (2)
  • Percentage (9-11)
  • NewPercentage (15-28)
openmeter/productcatalog/discount.go (2)
  • PercentageDiscount (21-24)
  • UsageDiscount (60-62)
openmeter/billing/service/lineservice/priceunit_test.go (2)
openmeter/billing/discount.go (4)
  • Discounts (78-81)
  • NewDiscountReasonFrom (154-191)
  • MaximumSpendDiscount (145-145)
  • PercentageDiscount (24-28)
openmeter/billing/invoicelinediscount.go (4)
  • LineDiscounts (312-315)
  • AmountLineDiscountManaged (104-107)
  • AmountLineDiscount (56-64)
  • LineDiscountBase (22-27)
openmeter/ent/db/billinginvoicelinediscount.go (4)
openmeter/billing/discount.go (3)
  • DiscountReasonType (128-128)
  • DiscountReasonType (136-142)
  • DiscountReason (147-152)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (9)
  • FieldRoundingAmount (41-41)
  • FieldQuantity (47-47)
  • FieldPreLinePeriodQuantity (49-49)
  • FieldAmount (39-39)
  • FieldReason (35-35)
  • FieldInvoicingAppExternalID (37-37)
  • FieldType (45-45)
  • FieldSourceDiscount (43-43)
  • ValueScanner (107-109)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (5)
  • FieldQuantity (67-67)
  • FieldAmount (35-35)
  • FieldInvoicingAppExternalID (73-73)
  • FieldType (61-61)
  • ValueScanner (249-251)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (5)
  • FieldQuantity (39-39)
  • FieldPreLinePeriodQuantity (41-41)
  • FieldReason (35-35)
  • FieldInvoicingAppExternalID (37-37)
  • ValueScanner (96-98)
openmeter/ent/db/billinginvoicelineusagediscount_query.go (4)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (3)
  • OrderOption (112-112)
  • FieldID (19-19)
  • FieldLineID (29-29)
openmeter/ent/db/billinginvoiceline_query.go (1)
  • BillingInvoiceLineQuery (29-50)
openmeter/ent/db/billinginvoiceline/where.go (3)
  • Name (92-94)
  • IDIn (32-34)
  • ID (17-19)
openmeter/ent/db/billinginvoicelineusagediscount/where.go (3)
  • LineID (91-93)
  • IDIn (31-33)
  • ID (16-18)
openmeter/billing/httpdriver/invoiceline.go (3)
openmeter/billing/invoicelinediscount.go (3)
  • LineDiscounts (312-315)
  • AmountLineDiscountManaged (104-107)
  • UsageLineDiscountManaged (254-257)
api/api.gen.go (6)
  • InvoiceLineDiscounts (3380-3390)
  • InvoiceLineAmountDiscount (3344-3368)
  • InvoiceLineAppExternalIds (3371-3377)
  • InvoiceLineUsageDiscount (3441-3470)
  • BillingDiscountReason (1067-1069)
  • Percentage (4688-4688)
openmeter/billing/discount.go (4)
  • DiscountReason (147-152)
  • MaximumSpendDiscountReason (131-131)
  • RatecardPercentageDiscountReason (132-132)
  • RatecardUsageDiscountReason (133-133)
openmeter/billing/service/lineservice/pricegraduatedtiered_test.go (2)
openmeter/billing/discount.go (3)
  • Discounts (78-81)
  • NewDiscountReasonFrom (154-191)
  • MaximumSpendDiscount (145-145)
openmeter/billing/invoicelinediscount.go (5)
  • LineDiscounts (312-315)
  • AmountLineDiscountManaged (104-107)
  • AmountLineDiscount (56-64)
  • LineDiscountBase (22-27)
  • LineMaximumSpendReferenceID (19-19)
openmeter/ent/db/billinginvoiceline_query.go (5)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (1)
  • OrderOption (285-285)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (1)
  • OrderOption (123-123)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (1)
  • OrderOption (112-112)
openmeter/ent/db/billinginvoicelineusagediscount_query.go (1)
  • BillingInvoiceLineUsageDiscountQuery (21-32)
openmeter/ent/db/billinginvoicelinediscount_query.go (1)
  • BillingInvoiceLineDiscountQuery (21-32)
openmeter/billing/discount.go (1)
openmeter/productcatalog/discount.go (3)
  • Discounts (113-116)
  • PercentageDiscount (21-24)
  • UsageDiscount (60-62)
openmeter/ent/db/ent.go (5)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (2)
  • Table (53-53)
  • ValidColumn (81-93)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (2)
  • Table (47-47)
  • ValidColumn (75-82)
openmeter/ent/db/billinginvoiceusagebasedlineconfig/billinginvoiceusagebasedlineconfig.go (2)
  • Table (31-31)
  • ValidColumn (46-53)
openmeter/ent/db/billinginvoice/billinginvoice.go (2)
  • Table (142-142)
  • ValidColumn (260-267)
openmeter/ent/db/billinginvoiceflatfeelineconfig/billinginvoiceflatfeelineconfig.go (2)
  • Table (27-27)
  • ValidColumn (40-47)
openmeter/productcatalog/discount_test.go (3)
api/api.gen.go (2)
  • Discounts (2020-2026)
  • Percentage (4688-4688)
openmeter/productcatalog/discount.go (3)
  • Discounts (113-116)
  • PercentageDiscount (21-24)
  • UsageDiscount (60-62)
api/client/go/client.gen.go (2)
  • Discounts (1891-1897)
  • Percentage (4384-4384)
openmeter/billing/adapter/invoicelines.go (2)
openmeter/ent/db/billinginvoicelineusagediscount_create.go (1)
  • BillingInvoiceLineUsageDiscountCreate (22-27)
openmeter/ent/db/billinginvoicelinediscount_create.go (1)
  • BillingInvoiceLineDiscountCreate (22-27)
openmeter/ent/db/billinginvoiceline/where.go (3)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (5)
  • Table (105-105)
  • LineUsageDiscountsTable (136-136)
  • LineUsageDiscountsColumn (141-141)
  • LineAmountDiscountsTable (143-143)
  • LineAmountDiscountsColumn (148-148)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/ent/db/billinginvoicelinediscount.go (2)
  • BillingInvoiceLineDiscount (19-63)
  • BillingInvoiceLineDiscount (86-105)
openmeter/billing/service/lineservice/discountpercentage.go (4)
openmeter/billing/discount.go (2)
  • Discounts (78-81)
  • PercentageDiscount (24-28)
api/api.gen.go (2)
  • Discounts (2020-2026)
  • Percentage (4688-4688)
openmeter/productcatalog/discount.go (2)
  • Discounts (113-116)
  • PercentageDiscount (21-24)
openmeter/billing/invoicelinediscount.go (2)
  • AmountLineDiscountManaged (104-107)
  • AmountLineDiscount (56-64)
openmeter/ent/db/billinginvoiceline_create.go (3)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (6)
  • Table (105-105)
  • LineUsageDiscountsTable (136-136)
  • LineUsageDiscountsColumn (141-141)
  • FieldID (19-19)
  • LineAmountDiscountsTable (143-143)
  • LineAmountDiscountsColumn (148-148)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (2)
  • Table (53-53)
  • FieldID (19-19)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (2)
  • Table (47-47)
  • FieldID (19-19)
openmeter/billing/adapter/invoicelinediff_test.go (4)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
openmeter/billing/invoicelinediscount.go (3)
  • AmountLineDiscountManaged (104-107)
  • LineDiscounts (312-315)
  • AmountLineDiscount (56-64)
pkg/models/model.go (1)
  • ManagedModelWithID (155-158)
openmeter/ent/schema/billing.go (2)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/ent/db/billinginvoicelinediscount.go (2)
  • BillingInvoiceLineDiscount (19-63)
  • BillingInvoiceLineDiscount (86-105)
openmeter/ent/db/migrate/schema.go (3)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (1)
  • Columns (173-206)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (1)
  • Columns (64-78)
openmeter/ent/db/billinginvoice/billinginvoice.go (1)
  • Columns (202-257)
openmeter/ent/db/billinginvoicelineusagediscount_delete.go (4)
openmeter/ent/db/ent.go (3)
  • IsConstraintError (361-367)
  • ConstraintError (345-348)
  • NotFoundError (278-280)
openmeter/ent/db/mutation.go (1)
  • BillingInvoiceLineUsageDiscountMutation (18699-18721)
openmeter/ent/db/predicate/predicate.go (1)
  • BillingInvoiceLineUsageDiscount (93-93)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (3)
  • Table (47-47)
  • FieldID (19-19)
  • Label (17-17)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (3)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (5)
  • FieldReason (35-35)
  • FieldInvoicingAppExternalID (37-37)
  • ReasonValidator (102-109)
  • OrderOption (112-112)
  • ByInvoicingAppExternalID (160-162)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (4)
  • FieldInvoicingAppExternalID (73-73)
  • FieldType (61-61)
  • OrderOption (285-285)
  • ByInvoicingAppExternalID (413-415)
openmeter/billing/discount.go (3)
  • DiscountReason (147-152)
  • DiscountReasonType (128-128)
  • DiscountReasonType (136-142)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (3)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (10)
  • FieldID (19-19)
  • FieldNamespace (21-21)
  • FieldCreatedAt (25-25)
  • FieldUpdatedAt (27-27)
  • FieldDeletedAt (29-29)
  • FieldChildUniqueReferenceID (75-75)
  • FieldDescription (33-33)
  • FieldInvoicingAppExternalID (73-73)
  • FieldQuantity (67-67)
  • Columns (173-206)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (14)
  • FieldID (19-19)
  • FieldNamespace (21-21)
  • FieldCreatedAt (23-23)
  • FieldUpdatedAt (25-25)
  • FieldDeletedAt (27-27)
  • FieldLineID (29-29)
  • FieldChildUniqueReferenceID (31-31)
  • FieldDescription (33-33)
  • FieldReason (35-35)
  • FieldInvoicingAppExternalID (37-37)
  • FieldQuantity (47-47)
  • FieldPreLinePeriodQuantity (49-49)
  • Columns (64-78)
  • ReasonValidator (113-120)
openmeter/billing/discount.go (3)
  • DiscountReason (147-152)
  • DiscountReasonType (128-128)
  • DiscountReasonType (136-142)
e2e/productcatalog_test.go (4)
api/api.gen.go (3)
  • DiscountPercentage (1954-1957)
  • Percentage (4688-4688)
  • Discounts (2020-2026)
pkg/models/percentage.go (2)
  • Percentage (9-11)
  • NewPercentage (15-28)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (1)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (3)
  • OrderOption (112-112)
  • Table (47-47)
  • FieldID (19-19)
openmeter/productcatalog/discount.go (6)
openmeter/billing/discount.go (1)
  • PercentageDiscount (24-28)
pkg/models/percentage.go (1)
  • Percentage (9-11)
pkg/models/error.go (1)
  • NewNillableGenericValidationError (129-135)
openmeter/productcatalog/price.go (1)
  • Price (84-91)
pkg/models/equaler.go (1)
  • Equaler (3-6)
pkg/models/clonable.go (1)
  • Clonable (3-5)
openmeter/ent/db/billinginvoicelineusagediscount.go (1)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (15)
  • Label (17-17)
  • FieldPreLinePeriodQuantity (41-41)
  • FieldQuantity (39-39)
  • FieldID (19-19)
  • FieldNamespace (21-21)
  • FieldLineID (29-29)
  • FieldChildUniqueReferenceID (31-31)
  • FieldDescription (33-33)
  • FieldReason (35-35)
  • FieldInvoicingAppExternalID (37-37)
  • FieldCreatedAt (23-23)
  • FieldUpdatedAt (25-25)
  • FieldDeletedAt (27-27)
  • FieldReasonDetails (43-43)
  • ValueScanner (96-98)
openmeter/ent/db/billinginvoiceline.go (4)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/ent/db/billinginvoicelinediscount.go (2)
  • BillingInvoiceLineDiscount (19-63)
  • BillingInvoiceLineDiscount (86-105)
openmeter/ent/db/billinginvoicelineusagediscount_query.go (1)
  • BillingInvoiceLineUsageDiscountQuery (21-32)
openmeter/ent/db/billinginvoicelinediscount_query.go (1)
  • BillingInvoiceLineDiscountQuery (21-32)
openmeter/ent/db/billinginvoicelinediscount_update.go (2)
openmeter/billing/discount.go (3)
  • DiscountReasonType (128-128)
  • DiscountReasonType (136-142)
  • DiscountReason (147-152)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (5)
  • FieldReason (35-35)
  • FieldInvoicingAppExternalID (37-37)
  • FieldType (45-45)
  • FieldQuantity (47-47)
  • FieldPreLinePeriodQuantity (49-49)
openmeter/ent/db/billinginvoicelinediscount_create.go (6)
openmeter/billing/discount.go (3)
  • DiscountReasonType (128-128)
  • DiscountReasonType (136-142)
  • DiscountReason (147-152)
openmeter/billing/invoiceline.go (1)
  • LineID (20-20)
openmeter/ent/db/billinginvoicelinediscount/where.go (4)
  • LineID (91-93)
  • Amount (111-113)
  • InvoicingAppExternalID (106-108)
  • Type (121-123)
openmeter/ent/db/billinginvoiceline/where.go (3)
  • Name (92-94)
  • Amount (102-104)
  • InvoicingAppExternalID (173-175)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (4)
  • FieldInvoicingAppExternalID (37-37)
  • FieldAmount (39-39)
  • FieldType (45-45)
  • FieldSourceDiscount (43-43)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (3)
  • FieldInvoicingAppExternalID (73-73)
  • FieldAmount (35-35)
  • FieldType (61-61)
openmeter/ent/db/setorclear.go (3)
openmeter/ent/db/billinginvoicelinediscount_update.go (2)
  • BillingInvoiceLineDiscountUpdate (22-26)
  • BillingInvoiceLineDiscountUpdateOne (451-456)
openmeter/billing/discount.go (1)
  • DiscountReason (147-152)
openmeter/ent/db/billinginvoicelineusagediscount_update.go (2)
  • BillingInvoiceLineUsageDiscountUpdate (22-26)
  • BillingInvoiceLineUsageDiscountUpdateOne (373-378)
openmeter/ent/db/client.go (4)
openmeter/ent/db/billinginvoicelineusagediscount_query.go (1)
  • BillingInvoiceLineUsageDiscountQuery (21-32)
openmeter/ent/db/billinginvoicelineusagediscount_create.go (1)
  • BillingInvoiceLineUsageDiscountCreate (22-27)
openmeter/ent/db/billinginvoicelineusagediscount_update.go (1)
  • BillingInvoiceLineUsageDiscountUpdate (22-26)
openmeter/ent/db/billinginvoicelineusagediscount_delete.go (1)
  • BillingInvoiceLineUsageDiscountDelete (16-20)
openmeter/ent/db/billinginvoiceline_update.go (2)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (1)
  • FieldID (19-19)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (1)
  • FieldID (19-19)
openmeter/billing/invoicelinediscount.go (6)
openmeter/billing/invoiceline.go (1)
  • LineExternalIDs (235-237)
openmeter/billing/discount.go (1)
  • DiscountReason (147-152)
pkg/models/validator.go (1)
  • Validate (16-26)
pkg/models/model.go (2)
  • ManagedModelWithID (155-158)
  • ManagedModel (107-113)
pkg/models/clonable.go (1)
  • Clonable (3-5)
pkg/models/error.go (1)
  • NewNillableGenericValidationError (129-135)
openmeter/ent/db/billinginvoicelineusagediscount_create.go (4)
openmeter/ent/db/mutation.go (1)
  • BillingInvoiceLineUsageDiscountMutation (18699-18721)
openmeter/billing/discount.go (3)
  • DiscountReasonType (128-128)
  • DiscountReasonType (136-142)
  • DiscountReason (147-152)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/billing/invoiceline.go (1)
  • LineID (20-20)
openmeter/ent/db/billinginvoicelinediscount/where.go (4)
openmeter/ent/db/predicate/predicate.go (1)
  • BillingInvoiceLineDiscount (79-79)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (2)
  • FieldInvoicingAppExternalID (73-73)
  • FieldType (61-61)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (4)
  • FieldInvoicingAppExternalID (37-37)
  • FieldType (45-45)
  • FieldReason (35-35)
  • FieldSourceDiscount (43-43)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (2)
  • FieldInvoicingAppExternalID (37-37)
  • FieldReason (35-35)
openmeter/ent/db/billinginvoicelineusagediscount_update.go (4)
openmeter/ent/db/mutation.go (1)
  • BillingInvoiceLineUsageDiscountMutation (18699-18721)
openmeter/ent/db/predicate/predicate.go (2)
  • BillingInvoiceLineUsageDiscount (93-93)
  • BillingInvoiceLine (65-65)
openmeter/ent/db/billinginvoicelineusagediscount/where.go (8)
  • ID (16-18)
  • UpdatedAt (81-83)
  • DeletedAt (86-88)
  • ChildUniqueReferenceID (96-98)
  • Description (101-103)
  • InvoicingAppExternalID (106-108)
  • Quantity (111-113)
  • PreLinePeriodQuantity (116-118)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (10)
  • UpdateDefaultUpdatedAt (92-92)
  • ReasonValidator (102-109)
  • FieldID (19-19)
  • FieldUpdatedAt (25-25)
  • FieldDeletedAt (27-27)
  • FieldChildUniqueReferenceID (31-31)
  • FieldDescription (33-33)
  • FieldInvoicingAppExternalID (37-37)
  • FieldQuantity (39-39)
  • FieldPreLinePeriodQuantity (41-41)
openmeter/ent/db/billinginvoicelineusagediscount/where.go (7)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/ent/db/predicate/predicate.go (2)
  • BillingInvoiceLineUsageDiscount (93-93)
  • BillingInvoiceLine (65-65)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (9)
  • FieldID (19-19)
  • FieldNamespace (21-21)
  • FieldCreatedAt (25-25)
  • FieldUpdatedAt (27-27)
  • FieldDeletedAt (29-29)
  • FieldChildUniqueReferenceID (75-75)
  • FieldDescription (33-33)
  • FieldInvoicingAppExternalID (73-73)
  • FieldQuantity (67-67)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (12)
  • FieldID (19-19)
  • FieldNamespace (21-21)
  • FieldCreatedAt (23-23)
  • FieldUpdatedAt (25-25)
  • FieldDeletedAt (27-27)
  • FieldLineID (29-29)
  • FieldChildUniqueReferenceID (31-31)
  • FieldDescription (33-33)
  • FieldInvoicingAppExternalID (37-37)
  • FieldQuantity (47-47)
  • FieldPreLinePeriodQuantity (49-49)
  • FieldReason (35-35)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (13)
  • FieldID (19-19)
  • FieldNamespace (21-21)
  • FieldCreatedAt (23-23)
  • FieldUpdatedAt (25-25)
  • FieldDeletedAt (27-27)
  • FieldLineID (29-29)
  • FieldChildUniqueReferenceID (31-31)
  • FieldDescription (33-33)
  • FieldInvoicingAppExternalID (37-37)
  • FieldQuantity (39-39)
  • FieldPreLinePeriodQuantity (41-41)
  • FieldReason (35-35)
  • FieldReasonDetails (43-43)
openmeter/billing/invoiceline.go (1)
  • LineID (20-20)
openmeter/billing/discount.go (2)
  • DiscountReasonType (128-128)
  • DiscountReasonType (136-142)
api/client/javascript/src/client/schemas.ts (4)
api/api.gen.go (12)
  • BillingDiscountReason (1067-1069)
  • BillingDiscountUsage (1072-1086)
  • BillingDiscounts (1089-1095)
  • DiscountReasonMaximumSpend (1960-1962)
  • DiscountReasonRatecardPercentage (1968-1981)
  • DiscountReasonRatecardUsage (1987-2002)
  • DiscountUsage (2012-2017)
  • Discounts (2020-2026)
  • InvoiceLineAmountDiscount (3344-3368)
  • InvoiceLineAppExternalIds (3371-3377)
  • InvoiceLineDiscounts (3380-3390)
  • InvoiceLineUsageDiscount (3441-3470)
api/client/go/client.gen.go (12)
  • BillingDiscountReason (965-967)
  • BillingDiscountUsage (970-984)
  • BillingDiscounts (987-993)
  • DiscountReasonMaximumSpend (1831-1833)
  • DiscountReasonRatecardPercentage (1839-1852)
  • DiscountReasonRatecardUsage (1858-1873)
  • DiscountUsage (1883-1888)
  • Discounts (1891-1897)
  • InvoiceLineAmountDiscount (3093-3117)
  • InvoiceLineAppExternalIds (3120-3126)
  • InvoiceLineDiscounts (3129-3139)
  • InvoiceLineUsageDiscount (3190-3219)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: E2E
  • GitHub Check: CI
  • GitHub Check: Developer environment
  • GitHub Check: Analyze (go)
🔇 Additional comments (571)
openmeter/ent/db/ent.go (1)

29-29: Nice job updating the import and database table validation.

The addition of the new billinginvoicelineusagediscount import and its corresponding entry in the column validation map aligns well with the PR objectives. This change supports the separation of unit and amount discounts into different tables, allowing for more precise management of discount types in the database.

Also applies to: 131-131

openmeter/ent/db/tx.go (2)

43-44: The addition of BillingInvoiceLineUsageDiscount client is consistent with the PR objectives.

This new client for handling usage-based discounts aligns with the PR goal of restructuring discounts to allow single discount per type and separating unit and amount discounts into different tables.


241-241: Proper initialization of the new client.

The initialization of the BillingInvoiceLineUsageDiscount client is correctly implemented in the init method, maintaining consistency with the initialization pattern used for other clients.

openmeter/ent/db/billinginvoiceline/where.go (4)

1896-1905: Function renamed to reflect specific discount type.

The function HasLineDiscounts has been properly renamed to HasLineUsageDiscounts to specifically target usage-based discounts, aligning with the PR's objective to separate discount types. This function now correctly references the LineUsageDiscountsTable and LineUsageDiscountsColumn constants.


1907-1917: Updated function signature to match new discount model structure.

The function HasLineUsageDiscountsWith (previously HasLineDiscountsWith) now appropriately accepts predicates of type BillingInvoiceLineUsageDiscount and uses the new newLineUsageDiscountsStep() helper. This change properly supports the database schema restructuring that separates unit and amount discounts.


1919-1928: New function added for amount-based discount filtering.

This new function HasLineAmountDiscounts implements the necessary predicate for querying invoice lines with amount-based discounts. It correctly implements the edge relationship using the appropriate table and column constants, supporting the PR's goal of separate discount type management.


1930-1940: New conditional filtering function for amount-based discounts.

The HasLineAmountDiscountsWith function completes the restructuring by providing conditional filtering for amount discounts, mirroring the pattern used for usage discounts. This ensures consistent query capabilities across both discount types.

openmeter/ent/db/runtime.go (3)

22-22: Added import for new billing invoice line usage discount package.

This import is correctly added to support the new BillingInvoiceLineUsageDiscount schema implementation, which is part of the database schema changes for separating different discount types.


498-499: Updated ValueScanner type for source discount.

The ValueScanner type for SourceDiscount is now updated to use billing.DiscountReason type, which aligns with the PR objective to modify the discount structure with both percentage and usage values.


504-533: Added BillingInvoiceLineUsageDiscount schema setup.

The implementation correctly adds the new schema for BillingInvoiceLineUsageDiscount, including all required validators and field descriptors. This change fulfills the PR objective of splitting unit and amount discounts into different tables for more precise management of null and non-null flags.

The schema setup follows the same pattern as other entities in the codebase, with proper namespace validators, timestamp handling, and ID generation. The ReasonDetails field using the DiscountReason type is particularly important for the new discount structure.

openmeter/ent/db/setorclear.go (6)

1136-1148: This code correctly handles null values for InvoicingAppExternalID.

The implementation follows the established pattern for handling nullable fields in database updates.


1164-1190: Good implementation of new discount handling patterns.

These methods allow for properly setting or clearing the source discount and type fields based on their nullability, aligning with the PR objective to modify the discount structure to permit only a single discount per type.


1220-1232: Proper implementation of time deletion handling for usage discounts.

The DeletedAt field is correctly implemented with the same null-checking pattern used throughout the codebase.


1234-1260: Good implementation of string field handlers for usage discounts.

The ChildUniqueReferenceID and Description fields follow the consistent pattern for handling nullable string values in the database.


1262-1274: InvoicingAppExternalID handler properly implemented for usage discounts.

The implementation correctly follows the same pattern used for the discount line handler version.


1276-1302: New quantity and reason handlers properly support the discount restructuring.

These methods provide the necessary support for the separation of unit and amount discounts into different tables as described in the PR objectives. The PreLinePeriodQuantity and ReasonDetails fields can now be properly set or cleared.

openmeter/ent/db/paginate.go (4)

494-538: Implementation correctly supports billing model restructuring.

This pagination method has been updated to work with BillingInvoiceFlatFeeLineConfig instead of what was likely previously BillingInvoiceDiscount, aligning with the PR's objective of restructuring the discount handling in the system. The implementation maintains the same pagination pattern used throughout the file.


542-586: Changes maintain consistency with pagination pattern.

The method properly follows the established pagination pattern while updating the type to work with BillingInvoiceLine. The implementation correctly handles limit, offset, cloning for count, and result aggregation.


590-634: Pagination properly implemented for updated discount model.

This method correctly implements pagination for the BillingInvoiceLineDiscount type, maintaining the established code pattern. The rename aligns with the PR goal of restructuring discounts to allow only a single discount per type.


638-682: Added support for usage-specific discounts.

The introduction of BillingInvoiceLineUsageDiscountQuery.Paginate properly supports the PR objective of separating unit and amount discounts into different tables. The implementation correctly follows the established pagination pattern and maintains consistency with other methods.

openmeter/ent/db/expose.go (1)

118-118:

Details

✅ Verification successful

Addition of BillingInvoiceLineUsageDiscount client aligns with the new discount structure.

This change adds the new BillingInvoiceLineUsageDiscount client as part of the broader restructuring to allow only a single discount per type. The new client will facilitate operations on the separated usage discount table, which is now distinct from amount discounts per the PR objectives.


🏁 Script executed:

#!/bin/bash
# Let's verify this is part of a complete transition by checking if BillingInvoiceDiscount 
# was removed and if there are corresponding references in the codebase

# Check for removed BillingInvoiceDiscount
git diff -- openmeter/ent/db/expose.go | grep -A 3 -B 3 "BillingInvoiceDiscount"

# Check for other instances of BillingInvoiceLineUsageDiscount across the codebase
rg "BillingInvoiceLineUsageDiscount" --type go

Length of output: 73150


BillingInvoiceLineUsageDiscount client addition validated and integrated consistently.

  • The new client is correctly instantiated in openmeter/ent/db/expose.go (line 118) using NewBillingInvoiceLineUsageDiscountClient(config).
  • Our diff check shows no lingering references to the removed BillingInvoiceDiscount within this file, indicating that this part of the migration is isolated.
  • A repository-wide search confirms that the BillingInvoiceLineUsageDiscount client is used extensively, which aligns with the PR’s objective of separating usage discounts from amount discounts.

Overall, the changes fulfill the intended restructuring, and no further modifications are necessary.

openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (7)

34-37: Adding back field constants for billing invoice line discounts.

The reintroduction of FieldReason and FieldInvoicingAppExternalID constants aligns with the PR objective to restructure the discount system by separating unit and amount discounts into different tables.


42-45: Reinstating source discount and type field constants.

These constants are correctly reintroduced to support the refactored discount structure, allowing for proper database field mapping.


73-74: Updating Columns slice with newly reinstated fields.

The addition of FieldReason and FieldInvoicingAppExternalID to the Columns slice ensures these fields are properly recognized as valid columns for database operations.


108-108: Updated ValueScanner type for source discount.

Changing from *billing.Discount to *billing.DiscountReason properly aligns with the PR objective of restructuring discounts, focusing on storing only the reason rather than the full discount.


113-115: Updated ReasonValidator function signature and valid cases.

The function now:

  1. Takes billing.DiscountReasonType instead of billing.LineDiscountReason
  2. Supports the expanded set of valid cases including "ratecard_percentage" and "ratecard_usage"

This properly supports the new discount structure mentioned in the PR objectives.


165-173: Added ordering functions for reason and invoicing app external ID.

These functions follow the established pattern for defining ordering options and are necessary for enabling sorting by these fields in database queries.


185-193: Added ordering functions for source discount and type.

These ordering functions properly enable sorting by the reinstated fields, maintaining consistency with the rest of the codebase.

openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (4)

1-2: Auto-generated code acknowledgment.
These lines indicate that this file is generated by Ent. Typically, direct manual edits are discouraged, as changes may be overwritten by future code generations.


74-82: Validity check approach.
The ValidColumn function correctly verifies columns against the defined list. This helps guard against malformed queries or column references.


101-109: Enum validation alignment.
The ReasonValidator correctly restricts the reason field to the known discount reasons (maximum_spend, ratecard_percentage, ratecard_usage). This preserves consistent usage of enum values and aligns with the new discount structure.


179-191: Ordering by BillingInvoiceLine.
The logic in ByBillingInvoiceLineField and newBillingInvoiceLineStep() ensures the query can order by a distinct field of the related billing_invoice_line. This is standard Ent practice and appears solid.

openmeter/subscription/repo/subscriptionitemrepo.go (1)

123-123: More robust discount validation

Changed from checking if input.RateCard.AsMeta().Discounts is nil to checking if it's empty using IsEmpty(). This ensures that discounts are only set when explicitly defined with content, not just when a pointer is non-nil but potentially contains an empty structure.

openmeter/subscription/repo/mapping.go (1)

122-122: Improved null safety for Discounts field

Changed default value from nil to an empty productcatalog.Discounts{} structure. This prevents potential nil pointer dereferences when working with the Discounts field and ensures a consistent representation of empty discounts throughout the codebase.

openmeter/billing/adapter/invoicelineprogressive.go (2)

12-13: Added imports for new discount types

Added necessary imports for the refactored discount structure, enabling separate handling of amount and usage discounts.


92-97: Split discount retrieval into amount and usage types

The original WithLineDiscounts() call has been replaced with separate calls for retrieving amount and usage discounts. This change aligns with the PR objective of allowing a single discount per type by splitting the discount storage into separate tables.

Each query now properly filters out deleted records with DeletedAtIsNil(), ensuring that only active discounts are considered in the invoice line processing.

openmeter/billing/invoiceline.go (1)

493-493: Simplified access to RateCardDiscounts field

Direct access to i.RateCardDiscounts instead of i.LineBase.RateCardDiscounts. Since Line embeds LineBase, this field is directly accessible from the Line struct and this change simplifies the code without altering functionality.

openmeter/billing/service/lineservice/pricevolumetiered_test.go (1)

397-410: Refactored discount structure for better type safety and clarity

The discount structure has been updated to use the new LineDiscounts type, which clearly separates amount-based discounts in a dedicated array field. This aligns with the PR objective of allowing a single discount per type while still maintaining the ability to record multiple amount discounts.

openmeter/subscription/testutils/ratecard.go (1)

96-98: Direct assignment of percentage discount improves clarity

The discount creation has been simplified by directly assigning a pointer to a PercentageDiscount structure rather than using the factory method. This change aligns with the PR objective of modifying the discount field in the ratecard to a new format that includes both percentage and usage values.

test/app/stripe/invoice_test.go (1)

561-565: Updated discount access to match new structure

The code now correctly accesses discounts through the Amount array field of the Discounts struct, rather than iterating directly over line.Discounts. This change is consistent with the PR objective of updating the discount structure on invoice lines.

openmeter/productcatalog/subscription/service/plan_test.go (1)

91-93: Simplified discount access and validation

The test now directly accesses the percentage discount via the Percentage field rather than using slice indexing and type conversion. This is more concise and less error-prone, aligning with the PR objective of modifying the discount structure within the subscription system.

openmeter/ent/db/addonratecard_create.go (1)

341-345: Added validation for the discounts field aligns with new discount structure.

This new validation check ensures that when discounts are specified, they're properly validated before an AddonRateCard is created. This supports the PR objective of allowing only a single discount per type by enforcing data integrity at the creation level.

pkg/models/model.go (1)

155-178: Well-structured model type for ID handling.

The new ManagedModelWithID type provides a clean abstraction for entities that need ID management. It includes proper validation and comparison functionality through the Validate() and Equal() methods. This supports the PR's restructuring of discount handling by providing a reusable base type for entities that need IDs.

openmeter/productcatalog/addon/ratecard_test.go (1)

120-126: Updated test code to use direct field assignments for the new discount structure.

The test code now directly assigns discount values to the appropriate fields in the Discounts struct instead of using factory methods. This aligns with the PR's objective of supporting a single discount per type by properly testing the new structure where a discount can have both percentage and usage components.

openmeter/ent/db/subscriptionitem_create.go (1)

407-411: Added validation for discounts in subscription items.

Similar to the changes in the AddonRateCard, this validation ensures that the discounts in subscription items are properly validated before creation. This is an important part of maintaining data integrity with the new discount structure that allows a single discount per type.

openmeter/productcatalog/plan/ratecard_test.go (1)

120-125: Discount structure updated to support single discount per type.

The code now directly creates the percentage and usage discounts as individual fields within the Discounts struct instead of using factory methods. This change aligns with the PR objective to modify the discount structure to permit only a single discount per type.

openmeter/ent/db/addonratecard_update.go (2)

360-364: Added validation for new discount structure.

Proper validation has been added for the discounts field in the AddonRateCard update operations. This ensures that any discount structure assigned to rate cards will be validated before persisting to the database, maintaining data integrity.


924-928: Added consistent validation in the single-item update method.

The same discounts validation logic has been applied to the AddonRateCardUpdateOne method, ensuring consistency between batch and single-item update operations.

openmeter/billing/service/lineservice/pricepackage_test.go (1)

243-256: Updated test case to use new line discount structure.

The test case now uses the new LineDiscounts structure that separates discounts by type. This change correctly implements the array-based approach for representing calculated discounts on invoice lines, which allows recording multiple amount discounts (for cases where both percentage and maximum spend discounts apply).

The updated structure provides better type safety by using strongly-typed discount categories (Amount) with appropriate arrays for each type, rather than a generic collection.

openmeter/productcatalog/subscription/http/mapping.go (1)

250-250: Simplified discount mapping with direct conversion.

The code now directly converts discounts from the rate card without intermediate variables or explicit error handling. This is possible because productcataloghttp.FromDiscounts() handles empty discounts gracefully by returning nil.

This simplification makes the code more readable while maintaining correct behavior for converting the new discount structure to API responses.

openmeter/billing/service/lineservice/pricedynamic_test.go (1)

188-201: Updated discount structure implementation looks good

The refactoring changes the way discounts are constructed in the test, aligning with the new discount structure where each discount type has its own field. The new implementation with billing.LineDiscounts structure containing an array of billing.AmountLineDiscountManaged matches the PR's goal of having a single discount per type.

openmeter/app/stripe/entity/app/invoice.go (2)

187-189: Correctly updated discount access pattern

Changed from using method call to direct field access, matching the refactored discount structure design. This simplifies the code and makes it clearer what type of discount is being processed.


296-297: Good adjustment to the new discount structure

Updated from line.Discounts.GetAmountDiscountsByID() to line.Discounts.Amount.GetByID(), properly aligning with the new discount structure. The change maintains the same functionality while making the discount type more explicit.

openmeter/billing/app.go (1)

219-229: Improved discount processing with the new structure

The refactoring simplifies the discount handling by:

  1. Directly accessing the Amount and Usage fields instead of iterating over generic discounts
  2. Setting external IDs directly on the discount objects without complex mutation logic
  3. Eliminating unnecessary error handling

This approach is more maintainable and makes the code more type-safe by being explicit about the discount types.

openmeter/ent/db/predicate/predicate.go (1)

92-104: Added database predicate for the new discount entity

The addition of BillingInvoiceLineUsageDiscount predicate type and its error handler follows the established pattern in the codebase and properly supports the database schema changes for separating discount types into different tables.

openmeter/billing/httpdriver/discounts.go (2)

34-47: Updated AsDiscounts function to handle the new BillingDiscounts structure

The function has been refactored to accept a pointer to the new api.BillingDiscounts type instead of a slice. This change correctly implements the new discount model where there can only be one discount per type (percentage or usage).

Good additions:

  • Proper nil check for the input pointer
  • Clear initialization of the output structure
  • Explicit handling for each discount type separately

49-61: Well-structured usage discount handling

The usage discount handling properly extracts and converts the discount information while maintaining good error handling. The code clearly handles the scenario where a usage discount exists in the input structure.

openmeter/billing/httpdriver/deprecations.go (2)

169-177: Updated discount processing in flat fee rate card handler

The code has been updated to use the new AsDiscounts function that accepts a pointer to api.BillingDiscounts instead of a slice. This change correctly aligns with the new discount model implementation where there can only be one discount per type.

The error handling is well implemented with a clear validation error message that includes the underlying error.


301-309: Updated discount processing in usage-based rate card handler

This change mirrors the update in the flat fee handler, ensuring consistent discount handling across different rate card types. The consistent approach to validation errors makes debugging easier.

openmeter/ent/db/subscriptionitem_update.go (2)

456-460: Added validation for discounts field

The validation logic for the Discounts field has been added to the check method of the SubscriptionItemUpdate struct. This ensures that any discounts added to a subscription item conform to the validation rules. The implementation follows the same pattern as other field validations, maintaining consistency in the codebase.


1154-1158: Added validation for discounts field in SubscriptionItemUpdateOne

The validation logic for the Discounts field has been consistently added to the SubscriptionItemUpdateOne struct as well, ensuring validation across both update methods. This consistency prevents potential validation gaps when updating subscription items.

openmeter/billing/service/lineservice/feeline.go (3)

44-51: Updated discount retrieval to support single discount per type

The code has been modified to retrieve a single discount instead of multiple discounts, aligning with the new discount model. The conditional check has been updated appropriately to check if the discount is nil rather than checking the length of a slice.


65-70: Updated line discount calculation for single discount

The discount calculation has been updated to work with a single discount instead of iterating through multiple discounts. The result is now correctly appended to the l.line.Discounts.Amount field, maintaining the expected behavior while using the new structure.


84-85: Updated discount total calculation

The calculation of DiscountsTotal has been updated to sum the Amount field of l.line.Discounts directly, rather than summing all discounts. This change correctly reflects the new discount structure and ensures accurate total calculations.

test/billing/discount_test.go (7)

111-115: Refactoring discount initialization to use the new structure

The test is now using direct assignment to the Percentage field in the RateCardDiscounts structure, which aligns with the PR objective of allowing a single discount per type.


133-135: Direct access to percentage discount is now more idiomatic

Accessing the discount directly through RateCardDiscounts.Percentage simplifies the code and removes the need for helper methods to extract the discount.


156-156: Test correctly verifies correlation ID persistence

The test now directly accesses the correlation ID from the percentage discount, ensuring it's properly retained during the invoice creation process.


161-161: Correlation ID verification for child lines is appropriately handled

The test correctly verifies that the correlation ID is propagated to all child lines in the progressive billing hierarchy.


168-175: Amount discount validation is comprehensive

The test now properly checks that the amount discount maintains the same correlation ID as its source percentage discount, validating the correct conversion between discount types.


186-190: Usage discount initialization follows the new pattern

The test correctly adds a usage discount to the existing discounts structure, maintaining consistency with the new discount model.


198-201: Correlation ID differentiation between discount types

The test verifies that different discount types have different correlation IDs, which is a critical aspect of the discount tracking system.

openmeter/productcatalog/ratecard.go (4)

126-126: Simplified discount cloning

The code now directly calls the Clone method on the Discounts struct, removing unnecessary conditional logic. This is cleaner and more maintainable.


199-201: Improved discount validation

The conditional check for discount length before validation has been removed, allowing validation to occur unconditionally. This ensures all discounts are always validated properly.


294-300: Enhanced discount validation for flat fee rate cards

The validation now explicitly checks that usage discounts are not allowed for flat fee rate cards, which is an important business rule that prevents incorrect discount configurations.


410-412: Streamlined usage discount validation for usage-based rate cards

The simplified validation logic directly checks if a usage discount exists for a flat price type, which is a clearer and more direct approach than the previous implementation.

openmeter/billing/service/discounts.go (2)

12-28: Simplified discount correlation ID generation

The function has been refactored to handle percentage and usage discounts separately, which aligns with the new discount structure of permitting only a single discount per type. This implementation is clearer and more maintainable.


31-42: Helper function for correlation ID generation

A new helper function generateCorrelationID encapsulates the logic for generating or validating correlation IDs, promoting code reuse and maintainability. The function properly handles empty correlation IDs by generating new ones and validates existing IDs.

openmeter/billing/service/lineservice/pricegraduatedtiered_test.go (2)

258-271: Updated discount structure in test expectations

The test now uses the new LineDiscounts structure with an Amount field containing a slice of AmountLineDiscountManaged, which aligns with the PR objective of restructuring discounts by type. This ensures that the tests validate the correct behavior of the new discount model.


279-292: Consistent usage of the new discount structure

The test maintains consistency by using the same discount structure pattern throughout all test cases. This ensures that all discount scenarios are properly tested with the new model.

openmeter/ent/db/hook/hook.go (1)

168-178: New adapter function matches the revised discount model architecture.

This new BillingInvoiceLineUsageDiscountFunc type replaces the removed BillingInvoiceDiscountFunc, aligning with the system-wide discount restructuring that separates usage discounts from amount discounts. The implementation follows the consistent pattern used for all adapter functions in this file.

test/billing/invoice_test.go (2)

2220-2226: Updated discount iteration to match the new discount model.

The code now properly iterates over the separate discount collections (Amount and Usage) rather than a single combined collection, aligning with the PR objective to separate discount types. This ensures all discounts are correctly processed when upserting an invoice.


2254-2260: Consistent implementation of the discount model in the finalization process.

This change correctly applies the same discount type separation pattern during invoice finalization, ensuring external IDs are properly associated with each type of discount. This maintains consistency with the changes made in the upsert operation.

openmeter/billing/service/lineservice/usagebasedline_test.go (5)

33-33: Updated discount structure in test case to match new model.

The ubpCalculationTestCase struct has been updated to use the new billing.Discounts type instead of an array of discounts, aligning with the system-wide discount model changes.


180-193: Restructured discount expectation to use the new discount model.

The test expectations have been updated to use the structured LineDiscounts type with separated amount and usage discount arrays. This properly reflects the new discount model architecture.


208-221: Consistent usage of the new discount model structure.

Similar to the previous test case, this expectation has been updated to match the new discount structure. The test now properly validates that maximum spend discounts are correctly added to the amount discount array.


236-249: Maintained test validation with updated discount structure.

This test case for 100% discount has been updated to follow the new discount model, validating that full discounts are properly represented within the amount discount array.


264-277: Consistent implementation in extreme overage test case.

The final test case also correctly implements the new discount structure when testing scenarios with significant overage, ensuring consistent behavior across all test scenarios.

openmeter/billing/service/lineservice/feeline_test.go (4)

22-27: Updated discount input to match new single discount per type model.

The test now uses a single PercentageDiscount object rather than an array, aligning with the PR objective to "allow single discount per type." The inclusion of a CorrelationID enables proper tracking and referencing of this discount.


32-49: Restructured expectations to validate the new discount model.

The test expectations have been updated to use the LineDiscounts structure with its Amount array, properly reflecting how percentage discounts are now converted to amount discounts for invoice lines.


56-56: Updated test input struct to reflect single discount model.

The generateFeeLineInput structure now accepts a single RateCardDiscount rather than an array, aligning with the PR's goal of allowing only a single discount per type.


69-71: Updated discount initialization to use the new structure.

The discount is now correctly assigned to the Percentage field of the Discounts struct using the Clone method, properly implementing the new discount model in the test fixture.

openmeter/billing/httpdriver/invoiceline.go (1)

492-532: Looks good.
The switch-case covers all known discount reason types comprehensively, returning clear errors for unknown types.

openmeter/ent/db/billinginvoicelineusagediscount_query.go (13)

1-32: No immediate correctness issues.
This file sets up the query builder, imports, and type definitions. Everything appears standard for an Ent-generated file.


34-86: Parameter chaining architecture is clear.
The methods (Where, Limit, Offset, Unique, Order, QueryBillingInvoiceLine) appear well-structured, providing straightforward query customizations.


87-130: Query convenience methods for the first entity.
These look standard and provide concise ways to get the first matching record or ID.


132-185: Only, OnlyX, OnlyID, and OnlyIDX methods
All follow the Ent pattern. Proper error handling for not singular and not found.


187-225: All, AllX, IDs, IDsX methods
No issues. The code is consistent with typical Ent usage for retrieving all records or just the IDs.


227-295: Count, CountX, Exist, ExistX, Clone, WithBillingInvoiceLine
Logic for counting, existence checks, and cloning the query builder is standard. The usage of interceptors suggests an extensible approach.


297-343: Aggregation and field selection
GroupBy, Select, and Aggregate methods are consistent with Ent's approach to grouping and partial selection of columns.


345-407: Query preparation and row fetching
The prepareQuery and sqlAll methods handle interceptors, enforce field validation, and retrieve results. Implementation looks correct.


409-437: Foreign-key loading
The loadBillingInvoiceLine function properly retrieves related billing invoice lines and attaches them to the edges.


439-527: sqlCount, querySpec, and sqlQuery
These methods define the specifics of the query structure, ordering, and field selection. They comply with Ent’s recommended pattern.


529-553: Locking mechanisms
The ForUpdate and ForShare methods implement row-level locking for Postgres. Implementation looks appropriate.


555-602: BillingInvoiceLineUsageDiscountGroupBy
GroupBy builder includes aggregation logic, column selection, and the standard scanning approach.


604-644: BillingInvoiceLineUsageDiscountSelect
Select builder is consistent with the rest of the Ent code, providing aggregated selection. No issues found.

openmeter/productcatalog/ratecard_test.go (7)

102-106: Valid percentage discount test
The code correctly checks a 10% discount scenario. Good coverage.


124-126: Invalid usage discount test
Assertions ensure that usage discounts are disallowed in this context. Good negative test.


268-275: Mixed discount test
Checks that a rate card can include both percentage and usage discounts without error. Good scenario coverage.


295-299: Invalid usage discount for flat price
Matrix testing approach ensures that usage discounts don’t apply incorrectly to a flat price. Nicely validated.


403-410: Percentage and usage discount definitions
Shows a scenario with combined discount types. Proper initialization and reusability.


456-457: Usage discount block
Defines usage discount quantity at 100. Straightforward test coverage.


563-567: Discount ordering irrelevance
Confirms that usage and percentage discount ordering doesn’t matter. Comprehensive test approach.

tools/migrate/migrations/20250411062903_billing-split-line-discounts.down.sql (3)

1-20: Database schema changes properly support new discount model.

The migration script correctly recreates the billing_invoice_discounts table with all necessary fields and indexes as part of the down migration. This aligns with the PR objective of separating unit and amount discounts into different tables for better management of null and non-null flags.


21-30: Proper cleanup of usage discount table and indexes.

The migration properly removes the indexes and the billing_invoice_line_usage_discounts table that were created in the forward migration. This ensures a clean rollback of the schema changes if needed.


31-33: Constraint and column property modifications correctly implemented.

The script properly reverts the changes to the billing_invoice_line_discounts table by modifying the constraints and column properties. The SQL syntax is correct and properly handles:

  1. Dropping the new foreign key constraint
  2. Setting column nullability requirements
  3. Adding back the original foreign key constraint

This ensures the table structure is properly restored to its original state.

test/billing/adapter_test.go (7)

647-681: Updated discount structure implementation looks good.

The code now uses the new LineDiscounts structure with separate Amount arrays of AmountLineDiscountManaged objects, aligning with the PR objective to permit only a single discount per type. The test correctly sets up three different amount discounts for testing.


694-696: Assertion update correctly validates the new discount structure.

The test now properly validates both the Amount and Usage discount collections separately, confirming the structural change from a single discount array to separate typed collections.


698-714: Discount mutation function looks good.

The code correctly uses the new mutate pattern to modify AmountLineDiscountManaged objects, removing the ManagedModelWithID fields before comparison. This allows for proper content comparison without being affected by database-generated fields.


719-728: Discount ID retrieval correctly implemented.

The new approach to find a discount by description is properly implemented. This ensures the test can maintain referential integrity when updating existing discounts.


729-768: Discount update test case handles all scenarios correctly.

The updated test properly covers three scenarios:

  1. Updating an existing discount with the same reference ID
  2. Updating an existing discount with an explicit ID reference
  3. Adding a completely new discount

This comprehensive testing validates the new discount structure handling.


792-822: Verification logic correctly uses the new discount accessor methods.

The test verification now uses the appropriate methods to locate and validate discounts, including:

  • Using GetDiscountByChildUniqueReferenceID for reference-based lookups
  • Using findAmountDiscountByDescription for description-based lookups
  • Proper verification of both changed and unchanged fields

This ensures the discount update functionality works as expected.


843-854: Helper method updated to match new discount type structure.

The helper method has been correctly renamed from findDiscountByDescription to findAmountDiscountByDescription and updated to work with the new AmountLineDiscountManaged type rather than the previous LineDiscount type.

api/openapi.yaml (11)

12147-12176: Validate New Discount Reason Schemas
The introduction of the new DiscountPercentage and DiscountReasonMaximumSpend schemas appears to align with the new discount structure. The requirements for a percentage field (with appropriate min/max values) and the enum for discount reasons seem accurate. Ensure that these validations meet the business logic expectations.


12250-12265: Verify Consolidated Discounts Schema Implementation
The new Discounts schema (lines 12250–12265) consolidates both percentage and usage discounts under one object. This aligns well with the PR objective of allowing a single discount per type. In future iterations, adding illustrative examples could further enhance clarity.


14721-14728: Verify Discount Schema Consistency in InvoiceFlatFeeRateCard
The InvoiceFlatFeeRateCard schema now includes a discounts property that references BillingDiscounts (lines 14723–14727). Please verify that using BillingDiscounts here (as opposed to Discounts used in other contexts) is intentional and aligns with the overall discount strategy.


14760-14769: Approve Addition of InvoiceLineAmountDiscount Schema
The newly added InvoiceLineAmountDiscount schema (lines 14760–14769) includes the required fields and appears well structured. Ensure that all downstream systems interpret the new schema correctly.


14798-14804: Confirm Updated Reason Field Reference
The reason property now references BillingDiscountReason (lines 14798–14804), which reflects the consolidation of discount reasons. This change is consistent with the new design.


17960-17967: Validate Discount Schema Reference for Flat Fee Rate Cards
The discounts property (lines 17960–17967) now references Discounts instead of BillingDiscounts. Please confirm that this naming difference is intentional and that it reflects the design choice whereby flat fee rate cards support only percentage discounts.


18115-18122: Confirm Consistent Use of Discounts Schema in Rate Cards
Similar to hunk 15, the discounts property here (lines 18115–18122) references Discounts. Verify that the distinction from BillingDiscounts is deliberate and documented.


19368-19375: Approve Discount Integration in Price Schema
The integration of the discounts property (lines 19368–19375) with a reference to Discounts within the price schema appears correct and consistent with the new unified discount structure.


19487-19494: Review Plan-Level Discount Field
The plan schema’s discounts field (lines 19487–19494) referencing Discounts is defined consistently with similar objects. The pattern and description are clear.


19527-19534: Confirm Discount Representation in Plan Duration
The discounts field (lines 19527–19534) within the plan duration section appears to be handled consistently with the rest of the document. No changes needed.


19609-19616: Ensure Downstream Compatibility for Plan Discounts
The discounts attribute in the final plan schema (lines 19609–19616) correctly references Discounts. Please verify that any downstream processing or validation logic is updated to accept the revised discount structure.

openmeter/ent/db/migrate/schema.go (3)

794-794: Foreign key symbol naming looks acceptable
The foreign key symbol is quite long but still under PostgreSQL’s 63‐character limit, so there should be no issues in practice.


819-823: Validate partial index criteria
This addition enforces uniqueness only when child_unique_reference_id is not null. If multiple null records for the same line are permissible, this is correct. Otherwise, you may need a different approach. Please confirm this is intended behavior.


2365-2365: Link usage discounts to invoice lines
Referencing the usage discounts table back to the invoice lines table with cascade deletion ensures orphan records are avoided. This is consistent with existing schema design.

api/openapi.cloud.yaml (8)

14653-14659: Ensure Correct Integration of BillingDiscounts in InvoiceFlatFeeRateCard.
Integrating BillingDiscounts as the value for the discounts property is consistent with the overall refactor. Verify that the default values (noted earlier in the snippet) and the descriptive text align with the updated discount handling logic.


14692-14705: Review InvoiceLineAmountDiscount Schema Integration.
The new InvoiceLineAmountDiscount schema—requiring fields like createdAt, updatedAt, id, reason, and amount—is well introduced. Confirm that its design aligns with the overall invoicing discount model and that all properties are handled as intended downstream.


14730-14736: Verify Use of BillingDiscountReason in Amount Discount.
The reason field in this section now correctly references BillingDiscountReason and is marked readOnly. Ensure that this integration is consistent with other parts of the schema and that consumers understand its purpose clearly.


14742-14786: Review InvoiceLineDiscounts and Related Schemas.
The grouping of InvoiceLineAmountDiscount, InvoiceLineAppExternalIds, and InvoiceLineDiscounts into separate, clear objects is well executed. Confirm that the descriptions (e.g., “deduced from the total price of the line” for amount discounts and the analogous note for usage discounts) are accurate and fully reflect the discount calculation order.


17934-17941: Review Discount Integration in Rate Card Configuration.
The rate card configuration correctly incorporates the discounts field via a reference to the Discounts schema. Ensure that the description “The discounts of the rate card” adequately communicates the behavior and that any default or null scenarios are handled per the new discount structure.


19295-19302: Review Discount Schema within Plan Configuration.
The plan object’s discounts field references the Discounts schema and is adequately documented. No additional changes are required, but please double-check that this integration aligns with consumer expectations.


19377-19384: Ensure Consistent Discount Field Definition in Plan Schema.
The discounts property is consistently defined here, and the accompanying regular expression for the resource identifier appears proper. Verify that the overall description fits the intended use cases and that similar definitions across the API remain uniform.


12375-12389:

Details

❓ Verification inconclusive

Review the Aggregated Discounts Schema.
The new top-level Discounts schema aggregates both percentage and usage discount details, which aligns with the PR objectives. Verify that its description (“Discount by type on a price”) and the accompanying explanations fully capture the intended billing behavior, particularly how usage discounts translate to “free” items until exhausted.


Verify Aggregated Discounts Schema Implementation
The aggregated Discounts schema in api/openapi.cloud.yaml now correctly combines the percentage and usage discount details. The description “Discount by type on a price” and the notes about the usage discount—clarifying that the first N items are effectively free until exhausted—accomplish the intended explanation of the billing behavior. Please verify that the referenced schemas (DiscountPercentage and DiscountUsage) align with the underlying discount logic and that any edge-case scenarios (e.g., discount exhaustion) are handled appropriately in the billing system.

openmeter/billing/adapter/invoicelinemapper.go (5)

163-163: Defaulting RateCardDiscounts to an empty struct is a good practice.
This change ensures that the RateCardDiscounts field is always initialized, preventing potential nil pointer issues. Looks good!


213-220: Good usage discount mapping block.
The logic properly iterates usage discounts, maps them using mapInvoiceLineUsageDiscountFromDB, and returns an actionable error on failure. This approach cleanly assigns the result to invoiceLine.Discounts.Usage.


222-228: Consistent handling of amount discounts.
The code similarly maps amount-based discounts, ensuring a parallel structure to usage discount handling. Error handling is consistent, enhancing maintainability.


233-269: mapInvoiceLineUsageDiscountFromDB function logic is sound.
The function correctly differentiates between maximum spend discounts with no reason details and other discount reasons with non-nil reason details. Explicit error handling for missing ReasonDetails is appreciated.


271-307: mapInvoiceLineAmountDiscountFromDB function logic is cohesive.
The approach mirrors usage discount handling, ensuring consistent error checks for the SourceDiscount field. Assigning default zero for RoundingAmount is a smart fallback.

openmeter/ent/db/billinginvoicelinediscount.go (8)

37-50: Introducing new fields for discount reasoning and referencing is consistent with single-discount-per-type logic.
The added fields for Reason, InvoicingAppExternalID, SourceDiscount, and Type appear aligned with the new discount structure, while the deprecation comments clarify usage of fields slated for removal. This is coherent with the PR's objectives.


52-58: Deprecating quantity fields for amount/usage table split.
Marking these fields as deprecated helps convey the new design, preventing confusion among developers regarding how discount quantity should be referenced moving forward.


90-94: Updated scanning logic for rounding amounts and quantities.
Refactoring the handling of numeric discount fields clarifies how these values are read, consistent with the single discount structure. No issues noted.


166-178: New case blocks for reason and invoicing fields.
These additions properly cast string values into the correct discount reason and external ID fields, with robust type checking and error reporting. This is vital for data consistency.


180-183: Improved handling of the amount field.
The logic ensures the scanned decimal is valid before assignment. This check helps avoid silent data corruption for the discount amount.


192-198: Mapping the SourceDiscount from scanned values.
The code properly delegates scanning to ValueScanner.SourceDiscount, returning an error if parsing fails, then assigns the resulting structure to bild.SourceDiscount. Good approach to keep the scanning logic separated.


199-204: Assigning the optional Type field.
This case block ensures type information is captured if present, reflecting the new discount approach. The fallback scenario is also handled gracefully when it's invalid.


287-321: Extending the String() builder to include discount fields.
By including reason, invoicing_app_external_id, amount, source_discount, type, quantity, and pre_line_period_quantity in the output, debugging becomes easier, providing a thorough textual record of the discount. This is a valuable addition.

openmeter/productcatalog/http/mapping.go (5)

75-75: Mapping new discount structure in RateCardFlatFee.
Calling FromDiscounts ensures the correct attachment of discount data, aligning with the new design. Solid approach.


107-107: Mapping new discount structure in RateCardUsageBased.
Similarly referencing FromDiscounts for usage-based rate cards promotes consistent discount handling across card types.


459-465: AsDiscounts call for flat.Discounts.
Introducing AsDiscounts(flat.Discounts) clarifies discount parsing, returning an error on invalid data to ensure robust data integrity.


513-519: Handling usage-based rate cards' discount field.
Extracting usage-based discounts via AsDiscounts(usage.Discounts) preserves a uniform code path for discount conversion.


523-545: New AsDiscounts function: streamlined discount processing.
The function gracefully handles nil discounts, usage discounts, and percentage discounts, returning a structured productcatalog.Discounts object. This significantly simplifies discount conversions without sacrificing error handling.

openmeter/billing/adapter/invoicelines.go (9)

18-18: No concerns with the new usage discount import.
Looks good as it enables the usage-discount functionality referenced below.


118-118: Conditional check on RateCardDiscounts is clear.
Only applies the discount field if non-empty. This looks correct.


224-226: Error handling for usage discount upsert is straightforward.
The wrapping of the error context is well done.


228-263: Check for consistent conflict handling in amount discounts.
Here we correctly use billinginvoicelinediscount.CreateBulk(...), referencing billinginvoicelinediscount.FieldID. The only questionable detail is ignoring billinginvoiceline.FieldCreatedAt instead of billinginvoicelinediscount.FieldCreatedAt, which may be a minor oversight if you intended to preserve the discount's original creation timestamp. Otherwise, logic looks solid.


264-268: Soft-delete approach for amount discounts is consistent.
Marking the discount's DeletedAt timestamp is aligned with typical soft-delete patterns.


271-271: Clear error message on amount discount upsert failure.
Good practice to wrap the underlying error.


279-279: Updating updated_at ensures correct last-modified tracking.
This is a good practice to maintain accurate timestamps.


291-291: Refetching lines post-upsert is prudent.
Helps return the most up-to-date state after database changes.


429-434: Appending usage discounts with Where(...DeletedAtIsNil()).
This ensures only active usage discount entries are included for expanded line items.

openmeter/billing/discount.go (12)

76-76: Interface assertion for Discounts is fine.
Verifies that Discounts correctly implements models.Clonable.


78-82: Discounts struct definition looks clean.
Organizes percentage and usage discounts under a single type.


83-95: Clone() method for Discounts is well-structured.
Correctly creates a deep copy of nested pointers.


101-111: Validation logic is straightforward.
Gracefully returns upon finding a non-nil discount field.


113-113: Comment for DiscountReason is minimal and fine.


114-114: discountReason interface name is clear.
Provides unambiguous contract for discount subtypes.


120-134: Interface methods for discountReason are logically distinct.
Makes it easy to access typed discount data (percentage, usage, etc.).


136-141: Values() function enumerates discount reason types.
Good to have a helper for all possible enumerations.


144-145: MaximumSpendDiscount placeholder type is acceptable.
Keeps the structure consistent with other discount subtypes.


147-300: DiscountReason struct and JSON methods are well-designed.
They ensure typed marshalling/unmarshalling for each discount category.


302-313: Validate() function covers all discount reason cases.
Handles recognized types properly and flags invalid ones.


97-99:

Details

✅ Verification successful

Verify IsEmpty() usage.
lo.IsEmpty(d) may behave unexpectedly for struct values. Confirm it truly checks if both Percentage and Usage are nil.


🏁 Script executed:

#!/bin/bash
# Searching for references to IsEmpty in the codebase
rg -A 3 'IsEmpty\('

Length of output: 11295


Discounts.IsEmpty: Confirmed Correct Behavior

I’ve verified that using lo.IsEmpty(d) for the Discounts struct is consistent with its intended use. The function properly returns true when both the Percentage and Usage fields are nil (i.e. the struct is at its zero state). Similar patterns throughout the codebase further support that this behavior is expected.

No changes are required.

openmeter/productcatalog/discount_test.go (14)

17-17: Migrating to Discounts field for test struct is consistent.
No issues identified.


22-26: Test coverage for valid percentage discount scenario is good.


30-34: Test coverage for valid usage discount scenario is good.


40-40: JSON serialization of Discounts is straightforward.
Uses standard library approach.


45-45: Unmarshalling into a zero-value Discounts struct is correct.


49-49: Equality check confirms round-trip JSON correctness.


65-69: Percentage discount equality test (left side) is valid.


71-74: Percentage discount equality test (right side) mirrors the left side.


80-82: Differing discount type (percentage vs usage) ensures negative test coverage.


85-87: Confirms that usage discount differs from a percentage discount.


110-114: Valid percentage discount within constraints (0–100%).


118-125: Catches invalid discount exceeding 100%.
Properly expects an error.


127-135: Valid usage discount test is correct.
Ensures usage-based discount is recognized.


139-141: Detects negative usage discount as invalid.
Good coverage of edge cases.

api/client/javascript/src/client/schemas.ts (20)

2330-2341: Looks good: correlation ID documentation improvements and discount reason union.
These clarifications for progressive billing help maintain discount consistency across invoices, and the updated BillingDiscountReason union aligns well with the single-discount-per-type approach.


2356-2358: Well-structured introduction of BillingDiscounts.
The correlation ID documentation clarifies usage in progressive billing, and consolidating percentage and usage discounts under BillingDiscounts is consistent with the new architecture.

Also applies to: 2363-2369


3401-3463: Comprehensive addition of new discount types and correlation ID references.
The new DiscountPercentage and DiscountReason* types are clearly documented, and the correlation ID logic for progressive billing is consistent.


3478-3484: Unified Discounts type.
Introducing a single type with optional percentage and usage fields simplifies handling multiple discount forms. This aligns with the PR’s single-discount-per-type goal.


4978-4978: Invoice line discounts reference.
Exposing InvoiceLineDiscounts in the invoice item schema maintains consistency with the new discount structure.


5197-5197: BillingDiscounts usage in invoice lines.
Linking the unified discount structure here ensures seamless discount handling for quantity-based lines.


5218-5218: Introduction of InvoiceLineAmountDiscount.
Defining a clear amount-based discount type is consistent with the broader single-discount-per-type changes.


5247-5275: Enhanced InvoiceLineDiscounts.
Combining amount and usage arrays in this structure elegantly supports multiple discount modalities on a single line.


5320-5368: New documentation for InvoiceLineUsageDiscount.
Details on timestamps, correlation ID, and usage quantity handling are thorough and align with progressive billing requirements.


5742-5742: Extended discounts field in the invoice item schema.
Allowing the line-level discount array fosters flexibility for lines that can have multiple discount entries.


5935-5935: Optional BillingDiscounts addition.
Applying the consolidated discount structure at this line level is in line with the new single-per-type approach.


7448-7448: Adopting Discounts in the rate card.
Including both percentage and usage discount fields here aligns with the rate card’s extended discount coverage.


7567-7567: Usage-based rate card discounts.
The newly introduced Discounts object ensures usage-based or percentage-based discounts can both be captured.


8587-8587: Subscription Item Discounts.
Extending the subscription item to accommodate both amount and usage discounts supports more granular discount configuration.


8646-8646: Plan-level discount unification.
The discounts field now uses the unified structure, which helps maintain a consistent discount model.


8704-8704: Phase-based plan discount unification.
Implementing discounts with a single type clarifies discount logic in phased billing structures.


9264-9268: Exposure of BillingDiscounts and reason fields.
Redefining the discount reason and usage aligns with the shift to a single discount data model.


9379-9387: New discount reasons and Discounts export.
Exporting DiscountReasonMaximumSpend, DiscountReasonRatecardPercentage, DiscountReasonRatecardUsage, DiscountUsage, and Discounts extends the client’s coverage of the newly consolidated discount structures.


9479-9484: New exports for invoice line discounts.
InvoiceLineAmountDiscount and InvoiceLineDiscounts provide improved clarity for line-level discount details.


9493-9494: Export of InvoiceLineUsageDiscount.
This final addition ensures usage-based discounts are fully covered in the client schema exports.

openmeter/billing/service/lineservice/discountpercentage.go (3)

19-26: Looks good for single-discount flow.
This approach correctly checks for a nil discount and safely returns without mutating further.


34-41: Ensure discount pointer usage remains safe.
Since we skip if discount is nil, dereferencing with *discount is guarded, and appending to l.Discounts.Amount is consistent with the new single discount approach.


69-83: Comprehensive percentage validation.
The check for discount bounds between 0% and 100% is straightforward and prevents invalid usage. Implementation appears correct.

openmeter/ent/db/billinginvoicelineusagediscount_delete.go (1)

1-89: Standard Ent delete builder looks correct.
The generated file follows typical patterns for predicate-based deletion. No issues found.

openmeter/billing/adapter/invoicelinediff.go (5)

60-62: Utility method for empty diffs.
Providing an IsEmpty() check is a helpful convenience for subsequent logic.


351-376: Centralized handling of line-dependent discounts.
Combining usage and amount discount diffs into out is coherent. No major concerns.


378-381: Interface for diffable discounts.
Requiring standard methods like GetID and ContentsEqual is a clean design for discount objects.


383-386: Result struct is clear.
The struct neatly encapsulates the constructed diff and affected line IDs.


423-476: Database vs. current discount sets.
The creation, deletion, and update steps are well-defined. The use of maps for IDs appears efficient.

tools/migrate/migrations/20250411062903_billing-split-line-discounts.up.sql (6)

1-2: Confirm data migration or retention for usage discounts.
These lines remove usage discounts from the old table without migrating them. Verify that the deleted data is genuinely no longer needed or has already been migrated to a new store.


5-6: Multiple modifications in one ALTER statement look fine.
The statement drops a constraint, changes defaults, and modifies columns in a single command. This is valid syntax, but ensure no migration conflicts occur, especially if large data volumes exist.


7-8: Dropping the default after setting it temporarily.
You set a default of 0 for the "amount" column and then immediately remove it. If this was done to handle existing records, please confirm no new rows are inserted during the step.


10-26: New usage discounts table looks well-structured.
The table columns and primary key definition align with the single-discount-per-type approach. The foreign key constraint and referencing columns appear correct.


28-34: Index creation is consistent with the usage discount model.
These unique and non-unique indexes help ensure quick lookups by ID, namespace, and references. This is good for performance.


37-37: Verify the removal of the old billing_invoice_discounts table.
Dropping this table might remove data that was still relevant or not fully migrated to the new structure. Confirm data integrity and that references have been fully replaced.

openmeter/ent/schema/billing.go (5)

22-23: New JSONStringValueScanner usage.
Defining scanners for *billing.Discounts and *billing.DiscountReason centralizes JSON (un)marshalling, improving consistency.


429-431: Separate edges for usage-based vs. amount-based discounts.
Defining line_usage_discounts and line_amount_discounts clarifies the distinction between discount types. Ensure all the existing code referencing line discounts has been updated to handle these new edges.


513-541: Introducing BillingInvoiceLineDiscountBase for shared discount fields.
Centralizing these fields under one mixin schema is a clean approach that consolidates common columns (line_id, description, etc.).


557-605: Field definitions with deprecated placeholders.
Including deprecated fields (like “type”, “quantity”, etc.) for backward compatibility is reasonable. Marking them clearly as deprecated is helpful in avoiding accidental usage.


627-686: Usage discount model introduced.
This new schema mirrors the usage discount DB table, reflecting the “single discount per type” approach. The custom value scanner references, reason details, and other fields align with the updated discount logic.

openmeter/productcatalog/discount.go (4)

8-8: Using github.com/samber/lo for convenience utilities.
This library simplifies pointer usage (e.g. lo.ToPtr) and emptiness checks. Be sure it doesn't introduce unintended overhead.


26-38: PercentageDiscount validation boundaries.
Rejecting values outside [0,100] prevents invalid or nonsensical discounts. This is correct and well-handled.


114-116: Consolidated Discounts struct.
By storing either a PercentageDiscount or UsageDiscount, the code enforces a single discount per type. This matches the new approach.


118-190: Lifecycle methods for Discounts.
The Equal, Clone, Validate, ValidateForPrice, and IsEmpty methods provide a complete set of operations to manage discount data. The usage of lo.IsEmpty is neat for quick checks.

openmeter/billing/invoicelinediscount.go (30)

23-26: Struct field additions
These newly added fields (Description, ChildUniqueReferenceID, ExternalIDs, Reason) appear consistent with the updated discount structure.


32-33: Validation logic
Ensuring Reason.Validate() is called and errors appended is a solid approach.


47-49: Getter for ChildUniqueReferenceID
Simple and clear method for retrieving the child reference ID.


52-53: LineDiscountBaseManaged
Embedding ManagedModelWithID aligns with the new managed model approach and ensures consistent ID tracking.


105-106: AmountLineDiscountManaged
Again, embedding ManagedModelWithID together with AmountLineDiscount maintains consistency for managed fields.


120-120: Equality check
Validating ManagedModelWithID equality is essential for accurate model comparison.


133-134: Clone method
Clones the embedded structs correctly, preventing unintended side effects.


138-140: ContentsEqual
Focuses on discount data equality rather than managed fields. Good for partial comparisons.


142-144: GetManagedFieldsWithID
Exposes embedded managed fields, facilitating ID reuse and change tracking.


146-151: WithManagedFieldsWithID
Allows updating managed fields while retaining the discount data.


153-159: AmountLineDiscountsManaged + Clone
Uses lo.Map to replicate items, ensuring an immutable approach to updating.


161-168: SumAmount
Sums amounts with rounding, a sensible approach for currency calculations.


170-178: GetByID
Collects discounts into a map keyed by ID. The O(n) approach is typical given the presumably small size.


180-188: GetDiscountByChildUniqueReferenceID
Performs a linear search by child reference ID. Straightforward for smaller arrays.


190-203: Mutate
Clones the collection before applying each mutator, preventing side effects on the original slice.


255-256: UsageLineDiscountManaged
Analogous to the amount discount approach, embedding managed fields and usage discount data.


270-279: Equal
Checks both the managed model and usage discount fields properly.


283-284: Clone
Mirrors the cloning logic used in amount discounts, ensuring consistent behavior.


288-289: ContentsEqual
Similar approach to compare usage discount content ignoring managed data.


292-293: GetManagedFieldsWithID
Simple accessor for retrieving the embedded managed model fields.


296-300: WithManagedFieldsWithID
Offers a clean way to reuse or reset managed fields.


303-304: UsageLineDiscountsManaged
Defines a slice of usage-based discount items.


305-305: LineDiscounts doc comment
Indicates a collection of line discounts aggregated together.


307-309: Interface conformance
Implements models.Clonable and models.Validator for LineDiscounts.


312-315: LineDiscounts struct
Holds separate lists for amount-based and usage-based discounts.


317-330: Clone method
Clones both amount and usage slices to maintain immutability.


335-351: Validate method
Aggregates validation results across both discount lists, returning combined errors.


353-369: ReuseIDsFrom
Attempts to match existing discount entries by unique reference ID and reuse their IDs.


370-372: IsEmpty
Checks for an empty discount by verifying both slices are zero-length.


374-426: Utility functions for ID reuse
Implements the logic to reuse or clear managed fields based on child references.

openmeter/ent/db/billinginvoicelineusagediscount_update.go (76)

1-19: File header and imports
Auto-generated by Ent; typically no manual edits needed.


21-26: BillingInvoiceLineUsageDiscountUpdate struct
Holds configuration and mutation logic for updates.


28-32: Where method
Appends predicates to filter the update operation.


34-38: SetUpdatedAt
Sets the timestamp for the updated_at field. Straightforward.


40-44: SetDeletedAt
Assigns a deletion timestamp, used for soft deletion.


46-52: SetNillableDeletedAt
Only sets deleted_at if the given pointer is non-nil.


54-58: ClearDeletedAt
Clears deleted_at, unmarking the entity as deleted.


60-64: SetLineID
Sets the foreign key field for line association.


66-72: SetNillableLineID
Only sets line ID if not nil.


74-78: SetChildUniqueReferenceID
Assigns the unique reference ID for child references.


80-86: SetNillableChildUniqueReferenceID
Same logic, only sets if provided.


88-92: ClearChildUniqueReferenceID
Removes a previously set child reference ID.


94-98: SetDescription
Simple setter for the description field.


100-106: SetNillableDescription
Sets description only if non-nil.


108-112: ClearDescription
Clears description.


114-118: SetReason
Assigns the enum-based discount reason.


120-126: SetNillableReason
Ensures reason is set only if pointer is not nil, avoiding unintended overrides.


128-132: SetInvoicingAppExternalID
Sets the external ID for the invoicing app.


134-140: SetNillableInvoicingAppExternalID
Only assigns external ID if provided.


142-146: ClearInvoicingAppExternalID
Clears the invoicing app external ID field.


148-152: SetQuantity
Stores the numeric quantity for usage-based discounts.


154-160: SetNillableQuantity
Sets quantity only if non-nil.


162-166: SetPreLinePeriodQuantity
Establishes a discount quantity before the line period.


168-174: SetNillablePreLinePeriodQuantity
Assigns pre_line_period_quantity if provided.


176-180: ClearPreLinePeriodQuantity
Clears the previously set pre-line period quantity.


182-186: SetReasonDetails
Attaches an entire DiscountReason object.


188-192: ClearReasonDetails
Removes the reason details object.


194-198: SetBillingInvoiceLineID
Associates with a BillingInvoiceLine by ID.


200-203: SetBillingInvoiceLine
A convenience method that extracts ID from a BillingInvoiceLine entity.


205-208: Mutation
Exposes the underlying mutation object.


210-214: ClearBillingInvoiceLine
Removes the association to the billing invoice line.


216-220: Save
Executes the update query and returns the count of updated rows.


222-229: SaveX
Version of Save that panics on error, typical ent pattern.


231-235: Exec
Runs the update without returning the row count.


237-242: ExecX
Panics if Exec fails.


244-250: defaults
Sets updated_at if not already provided.


252-268: check
Runs validation checks, e.g., reason validation and ensuring required edges are not cleared.


270-370: sqlSave
Core logic that constructs the SQL update spec, applies field changes and edges, then executes.


372-378: BillingInvoiceLineUsageDiscountUpdateOne
Builder for updating a single entity rather than multiple.


380-384: SetUpdatedAt
Same logic as the multi-update, but specific to a single record.


386-390: SetDeletedAt
Marks the record as deleted via timestamp.


392-398: SetNillableDeletedAt
Only sets deleted_at if the value is non-nil.


400-404: ClearDeletedAt
Unsets the deleted_at field.


406-410: SetLineID
Sets the line relation by ID.


412-418: SetNillableLineID
Same as above, but guarded by nil checks.


420-424: SetChildUniqueReferenceID
Sets or updates child reference ID on the discount entity.


426-432: SetNillableChildUniqueReferenceID
Only assigns the child reference if non-nil.


434-438: ClearChildUniqueReferenceID
Clears the ID from the entity.


440-444: SetDescription
Sets the discount’s description.


446-452: SetNillableDescription
Assigns description only if not nil.


454-458: ClearDescription
Resets the description field.


460-464: SetReason
Sets the discount reason.


466-472: SetNillableReason
Omits assigning the reason if pointer is nil.


474-478: SetInvoicingAppExternalID
Sets the invoicing app’s external ID.


480-486: SetNillableInvoicingAppExternalID
Sets the external ID only if the pointer is non-nil.


488-492: ClearInvoicingAppExternalID
Removes external ID value from the record.


494-498: SetQuantity
Defines the usage discount quantity.


500-506: SetNillableQuantity
Same as SetQuantity, but guarded by nil checks.


508-512: SetPreLinePeriodQuantity
Assigns a discount quantity relevant to earlier usage in the line period.


514-520: SetNillablePreLinePeriodQuantity
Only sets the pre-line quantity if the pointer is non-nil.


522-526: ClearPreLinePeriodQuantity
Resets pre-line quantity to nil.


528-532: SetReasonDetails
Links additional structured discount reason details.


534-538: ClearReasonDetails
Removes reason details from the record.


540-544: SetBillingInvoiceLineID
Links to the invoice line by a given string ID.


546-549: SetBillingInvoiceLine
Convenience method: sets line ID from an entity.


551-554: Mutation
Exposes underlying mutation object.


556-560: ClearBillingInvoiceLine
Removes the line association.


562-566: Where
Attaches predicates for filtering the single-record update.


568-573: Select
Allows specifying which columns to return.


575-579: Save
Executes the update query and returns the updated entity.


581-588: SaveX
Panics if Save fails, following Ent’s convenience pattern.


590-594: Exec
Runs the update without returning the updated entity.


596-601: ExecX
Panics if Exec fails.


603-609: defaults
Ensures updated_at is set to default if not set.


611-627: check
Validates reason enums, reason details, and ensures required edges aren’t improperly cleared.


629-749: sqlSave
Core update logic for the single-entity builder, building the spec and applying field/edge updates.

openmeter/ent/db/billinginvoicelineusagediscount/where.go (16)

1-14: File header and imports
Auto-generated ent code for building predicates. Usually requires no manual changes.


15-69: ID-based predicates
These cover equality, inequality, containment, and case-folded checks for the primary key.


70-184: Namespace-based predicates
Allows filtering by namespace with multiple operators (EQ, NEQ, In, NotIn, Contains, etc.).


185-223: CreatedAt-based predicates
A variety of comparisons (EQ, NEQ, GT, etc.) to filter by creation time.


225-263: UpdatedAt-based predicates
Parallel to CreatedAt, includes EQ, NEQ, GT, GTE, etc. for update time.


265-315: DeletedAt-based predicates
Handles soft-deletion checks, including IsNil/NotNil for active vs. soft-deleted records.


315-379: LineID-based predicates
Covers line ID matching, substring checks, and case-folded variants.


385-453: ChildUniqueReferenceID-based predicates
Includes filters for presence/absence (IsNil/NotNil) and string comparisons.


455-528: Description-based predicates
EQ, NEQ, sub-string checks, IS NULL checks for discount descriptions.


530-558: Reason-based predicates
Covers enumerations for discount reason with In/NotIn checks.


560-633: InvoicingAppExternalID-based predicates
Filters external ID with contain/prefix/suffix, plus nil checks.


635-673: Quantity-based predicates
Covers decimal quantity comparisons and membership checks.


675-723: PreLinePeriodQuantity-based predicates
Similar to quantity, plus nil checks for optional usage.


725-733: ReasonDetailsIsNil / NotNil
Predicates to detect presence or absence of reason details.


735-756: HasBillingInvoiceLine / HasBillingInvoiceLineWith
Checks existence or matching of the related invoice line entity.


758-771: And, Or, Not
Logical composition operators for chaining multiple conditions.

openmeter/ent/db/planratecard_create.go (1)

325-329: Implementation looks good and aligns with PR objectives.

Adding validation for the Discounts field follows the same pattern used for other fields in this struct. This ensures that any discounts added to a PlanRateCard are properly validated before persisting to the database.

openmeter/ent/db/planratecard_update.go (2)

323-327: Change is consistent with create operation validation.

This validation logic for the Discounts field in the update path follows the same pattern as in the create path, ensuring consistency in how discounts are validated across operations.


806-810: Validation properly implemented for single-entity update.

Adds the same discount validation to the single-entity update path, ensuring all update operations validate the discounts field consistently.

api/spec/src/productcatalog/discounts.tsp (1)

55-71: Good implementation of the new discount model structure.

The new Discounts model elegantly implements the "single discount per type" requirement by consolidating different discount types (percentage, usage) as optional properties in a single object rather than using an array of discount objects. This structural change supports the PR objective while maintaining clean separation of discount types.

I like that the model is designed with future expansion in mind (commented out amount field) while keeping the current implementation focused on the immediate requirements.

api/spec/src/productcatalog/subscription.tsp (2)

174-174: Type change aligns with new discount model.

Changed the discounts property type from what was likely an array of discount objects to the new consolidated Discounts model, ensuring consistency with the "single discount per type" approach throughout the codebase.


239-239: Consistent implementation of the new discount model.

Changed the discounts field in the SubscriptionItem model to use the new Discounts type, maintaining consistency with the changes made throughout the codebase.

api/spec/src/productcatalog/ratecards.tsp (2)

117-119: Appropriate consolidation of discount types

The change from discounts?: DiscountPercentage[] to discounts?: Discounts aligns with the PR objective of allowing only a single discount per type. This unified structure will support both percentage and usage values in one property.


161-162: Consistent implementation of consolidated discount structure

This change correctly matches the modification made to the RateCardFlatFee model, ensuring consistency across rate card types. The new Discounts type provides a cleaner representation of discounts.

e2e/productcatalog_test.go (3)

188-190: Updated discount type matches new model structure

The switch from api.DiscountUsage to api.DiscountPercentage properly implements the new discount model. The use of models.NewPercentage(10) correctly initializes the percentage value.


205-205: Proper assignment to the new Discounts structure

This line correctly assigns the discount to the new consolidated Discounts structure, using the appropriate field for the percentage discount.


284-285: Test assertions updated for new discount structure

The assertions have been properly updated to validate the presence and value of the percentage discount in the new structure. The use of InexactFloat64() ensures proper decimal comparison.

api/spec/src/billing/invoices/invoice.tsp (3)

616-616: Unified discount structure for invoice lines

Changed from discounts?: InvoiceLineDiscount[] to discounts?: InvoiceLineDiscounts to align with the new single discount per type approach. This matches the architectural changes in the discount system.


715-715: Consistent discount structure in usage-based rate cards

Properly updated from discounts?: BillingDiscount[] to discounts?: BillingDiscounts to maintain consistency with the unified discount model throughout the system.


795-795: Updated discount structure for flat fee rate cards

Changed from discounts?: BillingDiscountPercentage[] to discounts?: BillingDiscounts, completing the consistent implementation of the discount structure across all relevant models.

openmeter/ent/db/billinginvoiceline_create.go (5)

21-21: Added import for new discount type

Added import for billinginvoicelineusagediscount to support the separated discount tables approach.


417-430: New method for usage-based discount relationships

The new AddLineUsageDiscountIDs and AddLineUsageDiscounts methods properly implement the separation of usage discounts into their own table, as specified in the PR objectives.


432-445: Added methods for amount-based discount relationships

These new methods implement the handling of amount discounts, properly supporting the separation of discount types into different tables. This provides better type safety and database schema organization.


838-853: Updated database edge handling for usage discounts

The createSpec method has been updated to correctly handle the new usage discount relationship. This ensures that database operations will properly maintain the relationships between invoice lines and their usage discounts.


854-869: Updated edge handling for amount-based discounts

The code correctly configures the database edge for amount discounts, using the appropriate table and column names for the relationship. This completes the implementation of the separated discount tables approach.

api/spec/src/billing/invoices/discounts.tsp (5)

24-24: Confirm adoption of the new discount reason type.
The shift to BillingDiscountReason aligns with the single-discount-per-type approach. Ensure all references to old enums are cleaned up throughout the codebase and all usage sites are updated.

Would you like a script to check for any lingering references to InvoiceDiscountReason?


40-57: Great consolidation into InvoiceLineDiscounts.
Separating amount and usage fields in one structure clarifies discount application. This also paves the way for simpler expansions later. No issues found here.


60-83: Usage discount name and doc look consistent.
The new InvoiceLineUsageDiscount model name is intuitive. Verify that progressive billing references (e.g., preLinePeriodQuantity) are validated upstream.


86-98: Amount-based discount updates look good.
Renaming to InvoiceLineAmountDiscount clarifies that it’s applied to monetary amounts, rather than usage metrics.


134-197: Robust typed union for discount reasons.
Defining BillingDiscounts, DiscountReasonType, and the discriminated union fosters extensibility. Everything here appears consistent with the single-discount-per-type goal.

openmeter/ent/db/billinginvoiceline_query.go (10)

20-20: New import for usage discount query is correct.
No issues with this addition; it’s necessary for the new usage discount features.


30-46: New fields for discount queries.
Adding withLineUsageDiscounts and withLineAmountDiscounts to the query struct is consistent with the new discount separation. Verify that older discount references are removed to avoid confusion.


193-213: QueryLineUsageDiscounts method looks correct.
The O2M edge declaration and pathing logic properly link usage discounts to invoice lines.


215-235: QueryLineAmountDiscounts method.
Similarly well-formed approach to the amount discount edge. Name is clear, matching the new schema structure.


489-505: Clone method updated for the new discount fields.
This ensures cloned queries also preserve discount-based relationships, preventing missed data in subsequent queries.


700-707: loadedTypes expansion is correct.
Increasing the array size and indexing usage/amount discount edges ensures they are tracked during eager loading.


773-781: Lazy-load usage discount objects.
This integration with loadLineUsageDiscounts is consistent with the rest of the code. Confirm that no concurrency issues arise if discounts are loaded alongside lines.


782-789: Lazy-load amount discount objects.
Same approach as usage discounts; consistent and clean.


971-1000: loadLineUsageDiscounts method.
Implementation matches typical ent O2M loading patterns. Seems correct for usage-based relationship.


1015-1015: Correct field reference for line amount discounts.
Ensures your SELECT/WHERE is properly referencing billinginvoiceline.LineAmountDiscountsColumn.

openmeter/ent/db/billinginvoiceline.go (6)

117-120: Separation of usage and amount discounts in edges.
The new edge fields clarify the discount type at a glance. This improves readability of the domain model.


129-130: Expanded loaded types array.
This is consistent with the addition of new discount edges.


185-192: LineUsageDiscountsOrErr accessor method.
Providing an explicit “or error” method is helpful for distinguishing an unloaded edge vs. an empty relationship.


194-201: LineAmountDiscountsOrErr accessor method.
Again, matches the usage discount approach. You’ve enforced strongly typed accessor semantics.


536-539: Querying usage discounts at the entity level.
This collocates well with the remaining query methods, ensuring consistent API usage.


541-544: Querying amount discounts at the entity level.
Parallel to the usage discount logic. No issues found.

openmeter/ent/db/billinginvoicelineusagediscount.go (6)

1-16: Standard Ent-generated package and import statements.
These lines appear to be automatically generated boilerplate for Ent. No issues noted.


18-49: New struct and edges for billing invoice line usage discounts.
The struct definition and edge configuration conform to Ent patterns. Field naming is clear and consistent.


73-93: scanValues function review.
Properly maps columns to the correct data types, leveraging NullScanner for decimals. This is a standard Ent approach, and looks correct.


95-191: assignValues function review.
All fields appear to be assigned correctly with type checks and error reporting for unexpected types. This follows typical Ent patterns and looks solid.


193-220: Value, QueryBillingInvoiceLine, Update, and Unwrap methods.
These are standard Ent helper methods. They appear correctly implemented with no evident issues.


222-280: String() method and final definitions.
Generates a helpful string representation. No issues discovered.

openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (8)

94-97: New edge constants for usage and amount discounts.
Both constants are clear, consistent with naming conventions, and align with the single-discount-per-type restructuring.


135-148: Database table definitions for line usage and amount discounts.
Well-named constants for table and column references. These definitions accurately match the new discount entity structure.


484-489: ByLineUsageDiscountsCount ordering function.
Provides a way to order by the count of associated usage discounts. Follows Ent patterns for ordering by edge relationships.


491-496: ByLineUsageDiscounts ordering function.
Implements ordering by usage discount terms. Straightforward and adheres to Ent’s order-by-neighbor approach.


498-503: ByLineAmountDiscountsCount ordering function.
Similar to its usage-based counterpart, this function is properly set up for ordering by amount discount counts.


505-510: ByLineAmountDiscounts ordering function.
Aligns with Ent’s neighbor-based ordering, mirroring the usage discount approach. No issues identified.


567-573: newLineUsageDiscountsStep function.
Defines an O2M relationship from billing lines to usage discounts. Matches the newly introduced entity references without issues.


574-580: newLineAmountDiscountsStep function.
Complements the usage discount relationship with an amount discount relationship. Implementation is consistent and correct.

openmeter/ent/db/client.go (12)

31-31: Added import for the new entity type

The import of the new billinginvoicelineusagediscount package enables working with the newly added entity type in the codebase.


93-94: Added client field for BillingInvoiceLineUsageDiscount

This change introduces a new client field for handling the BillingInvoiceLineUsageDiscount entity, which aligns with the PR objective of separating unit and amount discounts into different tables.


171-171: Initialized the new client in the init method

The initialization of the BillingInvoiceLineUsageDiscount client ensures it's properly set up when the main client is created.


303-303: Added the new client to transaction initialization

This ensures the new BillingInvoiceLineUsageDiscount client is available in transactions, keeping consistency with other entity clients.


362-362: Added the new client to BeginTx method

Similar to the transaction initialization above, this ensures the client is properly set up when starting a transaction with options.


421-423: Updated hook registration to include the new entity

This modification ensures that hooks (mutation hooks) will be applied to the new BillingInvoiceLineUsageDiscount entity as well.


442-444: Updated interceptor registration for the new entity

Similar to the hook registration, this ensures that interceptors (query interceptors) will be applied to the new entity.


487-488: Added mutation handling for the new entity

This change ensures that mutations (create, update, delete operations) on the new entity are properly handled.


2661-2675: Added query method for line usage discounts

This method enables querying the relationship between a BillingInvoiceLine and its associated BillingInvoiceLineUsageDiscount entities. The implementation follows the standard pattern for ent ORM relationship queries.


2677-2691: Renamed relationship to clarify discount type

The relationship query method has been updated to specifically reference "line_amount_discounts" which clarifies the purpose of this relationship now that discounts have been split into separate types.


2915-3062: Added complete client implementation for BillingInvoiceLineUsageDiscount

This is the core implementation of the new client for managing usage-based discounts. It follows the standard pattern for ent ORM clients with methods for creating, querying, updating, and deleting entities. The implementation is consistent with other entity clients in the codebase.


7472-7494: Updated hooks and interceptors structures

These updates ensure that the hooks and interceptors structures include the new entity, which is necessary for the proper functioning of hooks and interceptors with the new entity.

openmeter/ent/db/billinginvoicelinediscount_update.go (14)

114-118: Method for setting discount reason looks consistent.
No immediate issues; the method follows the standard builder pattern and leverages the billing.DiscountReasonType.


120-126: Nillable setter logic is consistent.
This ensures null safety by checking the pointer before setting. No concerns here.


134-140: Nillable setter logic for InvoicingAppExternalID is straightforward.
Implementation is consistent with ent’s pattern.


142-146: Clearing the InvoicingAppExternalID field is handled correctly.
Helps maintain a consistent approach to optional fields.


182-186: Method for setting SourceDiscount.
The usage of a billing.DiscountReason object is clear and consistent. Ensure all validations are handled upstream/downstream.


188-192: ClearSourceDiscount approach is correct.
No further issues noted.


208-212: Clearing the 'type' field.
Ensures backward compatibility until the field is fully removed.


363-365: Sets the reason enum in the SQL save step.
No issues; properly keeps reason in sync with the builder.


366-371: Handling InvoicingAppExternalID in the SQL layer.
Implementation aligns with the mutation pattern, clearing or setting as appropriate.


397-408: Sets or clears quantity and preLinePeriodQuantity.
Both are marked as deprecated. Maintain only if needed for backward compatibility.


817-819: Sets the reason enum for a single-entity update (UpdateOne).
Judicious usage of ent’s field setting approach.


820-825: Sets or clears InvoicingAppExternalID in the UpdateOne builder.
Consistent with multi-entity builder approach.


848-850: Clears the 'type' field in the UpdateOne builder.
Implementation is consistent.


852-862: Sets or clears quantity and preLinePeriodQuantity in UpdateOne.
No immediate concerns; consistent with the rest of the code.

openmeter/ent/db/billinginvoiceline_update.go (33)

20-20: Imports billinginvoicelineusagediscount package.
This import is needed for the new usage discount code references.


557-561: AddLineUsageDiscountIDs method.
No issues; typical ent pattern for adding edges by IDs.


563-570: AddLineUsageDiscounts method.
Appropriately calls AddLineUsageDiscountIDs after collecting IDs. Looks good.


572-576: AddLineAmountDiscountIDs method.
Maintains parallel structure for amount-based discounts.


578-585: AddLineAmountDiscounts method.
Similar approach as usage discounts. Straightforward.


652-656: ClearLineUsageDiscounts method.
Correctly delegates to the mutation to clear all usage discount edges.


658-662: RemoveLineUsageDiscountIDs method.
Implementation is consistent with standard ent approach for edge removal.


664-671: RemoveLineUsageDiscounts method.
No concerns; delegates removal with ID extraction.


673-677: ClearLineAmountDiscounts method.
Parallel approach for clearing edges for amount discounts.


679-683: RemoveLineAmountDiscountIDs method.
Typical ent edge removal pattern.


685-692: RemoveLineAmountDiscounts method.
Consistent pattern for removing discount edges by ID.


1044-1056: Clearing line_usage_discounts edges in sqlSave.
Ensures the O2M relationship is properly cleared when requested.


1057-1072: Removing line_usage_discounts edges by IDs (sqlSave).
Logic is appropriate for partial removal.


1073-1088: Adding line_usage_discounts edges in sqlSave.
Collects IDs and appends them to the spec for insertion.


1089-1101: Clearing line_amount_discounts edges (sqlSave).
Implements an O2M clear operation.


1102-1117: Removing line_amount_discounts edges by IDs (sqlSave).
Partial edge removal logic is consistent.


1118-1133: Adding line_amount_discounts edges in sqlSave.
Matches the approach for usage discounts.


1756-1761: AddLineUsageDiscountIDs (UpdateOne).
No concerns; aligns with multi-edge patterns.


1762-1769: AddLineUsageDiscounts (UpdateOne).
Collects IDs, then delegates to the prior method.


1771-1775: AddLineAmountDiscountIDs (UpdateOne).
Follows the same structure as usage discount.


1777-1784: AddLineAmountDiscounts (UpdateOne).
Fully consistent with usage discount approach.


1851-1855: ClearLineUsageDiscounts (UpdateOne).
Ok for removing all usage discount edges.


1857-1861: RemoveLineUsageDiscountIDs (UpdateOne).
Standard pattern for partial removal.


1863-1870: RemoveLineUsageDiscounts (UpdateOne).
Works as expected; no issues.


1872-1876: ClearLineAmountDiscounts (UpdateOne).
Clears the O2M edge for amount-based discounts.


1878-1882: RemoveLineAmountDiscountIDs (UpdateOne).
Checks for a valid slice, then removes.


1884-1891: RemoveLineAmountDiscounts (UpdateOne).
Implementation mirrors usage discount removal.


2273-2285: Clearing line_usage_discounts edges in UpdateOne sqlSave.
Ensures proper O2M behavior for usage discounts.


2286-2301: Removing line_usage_discounts edges by IDs in UpdateOne sqlSave.
Implementation aligns with standard ent approach.


2302-2317: Adding line_usage_discounts edges in UpdateOne sqlSave.
Same pattern as multi-edge usage discount addition in the main Update builder.


2318-2330: Clearing line_amount_discounts edges in UpdateOne sqlSave.
Follows the O2M clearing logic for the amount-based discount table.


2331-2346: Removing line_amount_discounts edges by IDs in UpdateOne sqlSave.
Removes partial edges, consistent with the ent approach.


2347-2362: Adding line_amount_discounts edges in UpdateOne sqlSave.
No concerns; parallels usage discount edge logic.

openmeter/ent/db/billinginvoicelineusagediscount_create.go (2)

1-2: Auto-generated Ent code

No issues found; this is typical Ent-generated scaffolding for creating an entity.


171-181: Valid mandatory edge to BillingInvoiceLine

This block properly enforces a mandatory reference to the parent BillingInvoiceLine, aligning with the requirement that each discount must be associated with a line.

openmeter/ent/db/billinginvoicelinediscount/where.go (38)

105-108: New InvoicingAppExternalID predicate is properly aligned with ent's pattern.
No concerns.


120-123: New Type predicate mirrors ent’s convention accurately.
No concerns.


545-549: ReasonEQ predicate follows typical ent usage.
No concerns.


551-555: ReasonNEQ predicate is correct and consistent.
No concerns.


557-564: ReasonIn predicate uses the correct approach for enumerating values.
No concerns.


566-573: ReasonNotIn predicate parallels the In version appropriately.
No concerns.


575-578: InvoicingAppExternalIDEQ predicate is well-defined.
No concerns.


580-583: InvoicingAppExternalIDNEQ predicate is correctly implemented.
No concerns.


585-588: InvoicingAppExternalIDIn predicate handles multiple string arguments properly.
No concerns.


590-593: InvoicingAppExternalIDNotIn predicate is consistent with its “In” counterpart.
No concerns.


595-598: InvoicingAppExternalIDGT predicate is logically correct.
No concerns.


600-603: InvoicingAppExternalIDGTE predicate meets typical ent usage.
No concerns.


605-608: InvoicingAppExternalIDLT predicate implements less-than check correctly.
No concerns.


610-613: InvoicingAppExternalIDLTE predicate aligns with ent’s standard approach.
No concerns.


615-618: InvoicingAppExternalIDContains uses the expected substring match.
No concerns.


620-623: InvoicingAppExternalIDHasPrefix predicate checks prefixes accurately.
No concerns.


625-628: InvoicingAppExternalIDHasSuffix predicate checks suffixes accurately.
No concerns.


630-633: InvoicingAppExternalIDIsNil predicate is consistent with ent’s null-check pattern.
No concerns.


635-638: InvoicingAppExternalIDNotNil predicate is correct for non-null conditions.
No concerns.


640-643: InvoicingAppExternalIDEqualFold handles case-insensitive equality.
No concerns.


645-648: InvoicingAppExternalIDContainsFold manages case-insensitive substring checks.
No concerns.


740-743: SourceDiscountIsNil predicate is suitably defined.
No concerns.


745-748: SourceDiscountNotNil predicate is suitably defined.
No concerns.


750-753: TypeEQ predicate is properly aligned with ent’s best practices.
No concerns.


755-758: TypeNEQ predicate is logically sound.
No concerns.


760-763: TypeIn predicate sets up an array-based match effectively.
No concerns.


765-768: TypeNotIn predicate complements the In logic appropriately.
No concerns.


770-773: TypeGT predicate is straightforward and correct.
No concerns.


775-778: TypeGTE predicate is straightforward and correct.
No concerns.


780-783: TypeLT predicate is aligned with the ent pattern for less-than checks.
No concerns.


785-788: TypeLTE predicate is aligned with ent’s standard approach.
No concerns.


790-793: TypeContains predicate accurately checks for substring matches.
No concerns.


795-798: TypeHasPrefix predicate is accurately implemented.
No concerns.


800-803: TypeHasSuffix predicate is accurately implemented.
No concerns.


805-808: TypeIsNil predicate is valid for null checks.
No concerns.


810-813: TypeNotNil predicate is valid for non-null checks.
No concerns.


815-818: TypeEqualFold predicate matches case-insensitively in a robust manner.
No concerns.


820-823: TypeContainsFold predicate correctly handles case-insensitive substring checks.
No concerns.

openmeter/billing/service/lineservice/usagebasedline.go (3)

355-355: Update to use the newly structured discount types.

The code has been modified to access the Amount field of the Discounts structure before calling SumAmount. This change aligns with the PR objective of restructuring discounts to allow a single discount per type, separating amount and usage discounts.


382-391: Updated discount creation to use the new discount structure.

The code now correctly uses the new AmountLineDiscountManaged type instead of the previous generic discount creation method. This change aligns with the separation of discount types (amount vs. usage) as outlined in the PR objectives.


396-405: Updated the second discount creation to use the new discount structure.

Similar to the previous change, this code now uses the new AmountLineDiscountManaged type for creating discounts. This ensures consistency in how discounts are represented throughout the codebase.

openmeter/billing/adapter/invoicelinediff_test.go (19)

23-23: Field renamed to reflect the new discount structure.

The field has been renamed from Discounts to AmountDiscounts to accurately represent its content and align with the PR objective of separating different discount types.


51-51: Updated test code to use the new discount structure.

The test initialization now uses the new newAmountDiscountsWithIDs function instead of the previous discount creation method.


87-89: Updated test expectation to use the new discount type.

The test case expectation has been updated to use AmountDiscounts instead of Discounts to align with the new discount structure.


121-124: Updated test expectations for discount deletion.

The discount deletion test expectation has been updated to use AmountDiscounts instead of Discounts to match the new structure.


179-179: Updated discount access pattern.

The code now accesses discounts through the new structure, using Discounts.Amount[0].ID instead of a direct field access pattern.


194-198: Updated test expectations for discount updates.

Test expectations for discount creation and deletion have been updated to use AmountDiscounts instead of Discounts.


208-208: Updated discount field access.

The code now correctly accesses discounts through the Amount field on the Discounts structure.


227-227: Updated discount accessor pattern.

The discount accessor pattern has been updated to reflect the new structure.


235-235: Updated test expectations for discount changes.

The test expectations for discount changes have been updated to use AmountDiscounts instead of Discounts.


246-250: Field access updated for the discount structure.

The discount field access pattern has been updated to match the new discount structure, accessing through the Discounts.Amount field.


257-261: Updated test expectations for detailed discount operations.

The test expectations have been updated to reflect the new discount structure, ensuring correct generation and verification of test cases.


281-283: Updated test expectations for discount deletion.

The test expectations for discount deletion have been updated to use AmountDiscounts instead of Discounts to match the new structure.


305-307: Updated test expectations for complex discount scenarios.

The test expectations for complex discount scenarios involving deletion of parent lines have been updated to use AmountDiscounts instead of Discounts.


384-392: Updated helper function for discount ID mapping.

The helper function for mapping discount IDs has been updated to work with the new AmountLineDiscountManaged type instead of generic discounts.


394-400: Updated diff helper function for discount types.

The helper function for creating diffs of discount types has been updated to work with the new discount structure.


402-413: Added helper function for message prefixing.

A new helper function msgPrefix has been added to improve test message formatting. This is a good addition that enhances test output readability.


418-420: Updated assertion helpers to use the new message prefix function.

The assertion helpers have been updated to use the new msgPrefix function for improved error messages.


430-430: Updated assertion helper for discount type.

The assertion helper has been updated to check AmountDiscounts instead of Discounts.


472-485: Replaced discount creation function with a new version.

The old newDiscountsWithIDs function has been replaced with newAmountDiscountsWithIDs, which creates discounts using the new LineDiscounts structure with an Amount field. This correctly aligns with the new discount structure.

openmeter/billing/service/lineservice/priceunit_test.go (4)

188-202: Updated test discount structure to match new implementation.

The test case has been updated to use the new discount structure with explicit LineDiscounts containing an Amount array. This directly initializes the discount structure according to the new design instead of using factory methods.


209-214: Updated discount initialization to use direct struct creation.

The discount initialization has been changed from a method-based approach to direct struct initialization, simplifying the code and making it more consistent with the new model structure.


233-235: Updated discount assignment to use the new structure.

The discount assignment has been updated to use the new Discounts structure with a Percentage field, correctly aligning with the PR's objective of structuring discounts by type.


249-272: Updated test expectations for discount calculations.

The test expectations for discount calculations have been updated to use the new structure, correctly handling both percentage discounts and maximum spend discounts within the new discount model.

openmeter/ent/db/billinginvoicelinediscount_create.go (29)

111-113: Use of billing.DiscountReasonType looks consistent.
The transition to billing.DiscountReasonType in SetReason aligns with the new structure, and the existing validator ensures valid inputs.


123-129: Nillable external ID logic is correct.
This pattern follows the standard ent approach for optional fields.


131-135: Confirm if negative amounts are allowable.
If discounts should never be negative, consider validation or mention it in the code.


151-156: Source discount logic appears sound.
The billing.DiscountReason validation is handled below, so no issues here.


157-162: Potential risk in using a raw string for the “type” field.
Consider an enum-like approach if you want to prevent invalid discount types.


163-170: Nillable type pattern is consistent.
It aligns well with the new single-discount approach.


289-290: Good enforcement of line_id requirement.
This ensures data integrity by rejecting incomplete discount records.


300-301: Enforcing required amount is beneficial.
Prevents logic errors from missing discount values.


374-378: Storing reason as an enum is commendable.
This helps maintain controlled discount reasons in the database.


379-381: InvoicingAppExternalID assignment is straightforward.
No issues found with the new field’s usage.


384-384: Amount property assignment is correct.
Successfully captures the discount amount for further usage.


398-408: Added logic for type, quantity, and pre_line_period_quantity.
Each field is handled in line with the single-discount approach.


557-561: Upsert: SetReason mirrors create logic.
Maintains consistency between creation and upsert flows.


563-567: Upsert: UpdateReason is fine.
No conflicts in updating reason in the upsert scenario.


569-573: Upsert: SetInvoicingAppExternalID matches the create pattern.
Implementation is consistent across create and upsert.


575-579: Upsert: UpdateInvoicingAppExternalID.
Properly allows updating external ID in upsert contexts.


581-585: Upsert: ClearInvoicingAppExternalID.
Good to have a clear method for optional fields.


617-619: Upsert: SetSourceDiscount parallels create.
Ensures a unified approach to source discount assignment.


623-625: Upsert: UpdateSourceDiscount logic is fine.
Keeps the discount reason in sync.


629-633: Upsert: ClearSourceDiscount.
Allows fully removing the discount reason, no concerns.


635-639: Upsert: SetType reaffirms usage of a string field.
Consider validating or restricting possible values.


641-645: Upsert: UpdateType.
No issues in matching the create logic.


647-651: Upsert: ClearType.
Consistent approach to removing the discount type.


653-657: Upsert: SetQuantity.
Mirrors create behavior, no issues spotted.


659-663: Upsert: UpdateQuantity.
Straightforward logic for quantity adjustments.


665-669: Upsert: ClearQuantity.
Properly clears out the discount quantity if no longer needed.


671-675: Upsert: SetPreLinePeriodQuantity.
Aligns with the new discount structure for usage metrics.


677-681: Upsert: UpdatePreLinePeriodQuantity.
No concerns updating usage-based discount data.


683-687: Upsert: ClearPreLinePeriodQuantity.
Consistent clearing logic, no issues here.

@turip turip force-pushed the refactor/allow-single-discount-per-type branch from 7951efc to 31123fb Compare April 11, 2025 07:10
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: 1

🔭 Outside diff range comments (1)
openmeter/ent/schema/billing.go (1)

543-605: 🛠️ Refactor suggestion

Evaluate handling of new discount struct with deprecated fields
The new BillingInvoiceLineDiscount includes fields marked deprecated. Consider isolating them or providing a clear migration path to avoid confusion long-term.

🧹 Nitpick comments (31)
openmeter/ent/db/billinginvoicelinediscount_update.go (4)

128-146: Consider validating InvoicingAppExternalID.

Since the invoicing_app_external_id references external systems, add checks (e.g., length constraints, format checks) to ensure valid data is stored.


194-212: SetType introduction is consistent but consider limiting possible values.

Storing the discount type as a free-form string can lead to inconsistent data. If the set of discount types is known, consider using a string-enum or custom validation for better integrity.


552-570: InvoicingAppExternalID setters for UpdateOne mirror the multi-update approach.

As above, consider adding validation for external IDs to prevent unforeseen issues (e.g., empty strings or invalid formats).


618-636: SetType in UpdateOne maintains consistency with the main builder.

Same consideration applies: enforce known discount types or apply validation to avoid inconsistent values in the database.

openmeter/billing/httpdriver/invoiceline.go (1)

428-490: Enhanced discount mapping with structured API response.

The function now returns a structured InvoiceLineDiscounts object that separates amount and usage discounts, rather than a flat list. This provides better organization of discount data in API responses and supports the PR goal of allowing only a single discount per type.

There's a small issue in the error message at line 483 - it says "amount discounts" when it should say "usage discounts" since it's in the usage discount mapping section.

-			return nil, fmt.Errorf("failed to map amount discounts: %w", err)
+			return nil, fmt.Errorf("failed to map usage discounts: %w", err)
api/openapi.yaml (8)

10588-10605: Clarify "BillingDiscountReason" Schema and Correlation ID Documentation.
The new block introduces the BillingDiscountReason schema using a oneOf composition and a discriminator to select between discount reason types. The in-line documentation regarding correlation ID auto-generation is informative; however, consider rephrasing “setups the discount amounts might be incorrect” for improved clarity (e.g. “…or the discount amounts may be computed incorrectly if modified”).


10627-10643: Introduction of the "BillingDiscounts" Composite Schema.
This hunk adds the BillingDiscounts schema that consolidates both percentage and usage discount properties. This design aligns with the single discount per type approach. Please ensure that both properties are validated downstream and that any documentation or examples clearly illustrate the expected object structure.


12182-12202: Addition of a Correlation ID to "DiscountReasonRatecardPercentage".
The updated schema now introduces a correlationId property with a specific regex pattern and detailed description. Verify that the pattern is consistent with other discount schemas and consider revising the phrase “setups the discount amounts might be incorrect” for enhanced clarity.


12209-12233: Improved "DiscountReasonRatecardUsage" Schema with Usage and Correlation ID.
This block expands the DiscountReasonRatecardUsage schema by adding a quantity field (with a note that it must be positive) and a correlationId field similar to the percentage counterpart. Please ensure that the phrasing in the description is consistent and clear across both schemas.


12253-12264: Consolidated "Discounts" Schema Design.
A new Discounts schema now aggregates the DiscountPercentage and DiscountUsage definitions. This consolidation supports the new single discount per type approach. Verify that both the percentage and usage paths are properly validated in processing logic.


14432-14436: Fix Typographical Error in Discounts Description.
The description “Discounts detailes applied to this line” contains a typo—“detailes” should be corrected to “details” for clarity and consistency.


14832-14851: "InvoiceLineDiscounts" Schema with Separated Discount Arrays.
The revised InvoiceLineDiscounts schema cleanly divides amount-based and usage-based discounts into separate arrays. Ensure that this structure is handled correctly in any discount aggregation or rendering logic.


15552-15558: Consistent Discounts Reference with Repeated Typo.
Again, the discounts field description includes the typo “Discounts detailes applied to this line.” Please update to “details” to maintain consistency throughout the document.

api/openapi.cloud.yaml (7)

10761-10778: Clarify and Improve Correlation ID Description in BillingDiscountReason
The new BillingDiscountReason schema is well structured with a discriminator and clear mappings. However, the multi‐line description for the correlation ID contains awkward phrasing (e.g. “setups the discount amounts might be incorrect”). Consider rewording it for clarity. For example: “If not provided, the invoicing engine will auto‐generate one. When editing an invoice line, please ensure the correlation ID remains unchanged; otherwise, discount amounts may be calculated incorrectly.”


10800-10816: Review of the BillingDiscounts Schema Definition
The BillingDiscounts object now cleanly aggregates both percentage and usage discounts. It would be beneficial to add a brief note explaining how the two properties interact if both are provided. Additionally, ensure the correlation ID guidance (as seen above) is consistent across all discount-related schemas.


12304-12328: Enhance DiscountReasonRatecardPercentage Details
The DiscountReasonRatecardPercentage schema now includes a correlationId field with a precise regex pattern. As in hunk 1, consider revising the correlationId description for readability and consistency. Additionally, the description “The reason for the discount is a ratecard percentage.” is clear, but a slight rewording (e.g. “indicates that the discount stems from a ratecard percentage”) might further improve clarity.


12334-12366: Consolidate and Clarify DiscountUsage Schema
The DiscountReasonRatecardUsage schema now includes a quantity property (with a note that it must be positive) and a correlationId. Again, the same phrasing issue in the correlationId description appears. Also, the new DiscountUsage schema is introduced immediately afterward; please verify that its intended purpose is distinct from any similarly named schemas and that the documentation clearly explains its role.


14364-14368: Fix Typographical Error in InvoiceLineDiscounts Description
The description “Discounts detailes applied to this line.” contains a typo (“detailes”). Please update it to “Discounts details applied to this line.”

-            Discounts detailes applied to this line.
+            Discounts details applied to this line.

14866-14939: Review Comprehensive InvoiceLineUsageDiscount Schema
The InvoiceLineUsageDiscount schema is detailed and covers various timestamps, identifiers, and discount reasoning. A minor grammatical improvement: change “an usage-based discount” to “a usage-based discount.” Consider updating the title for consistency.

- InvoiceLineUsageDiscount represents an usage-based discount applied to the line.
+ InvoiceLineUsageDiscount represents a usage-based discount applied to the line.

15484-15491: Reapply Typo Correction in Discounts Description
This hunk again contains the typo “detailes” in the discounts property description. Please correct it as noted earlier.

e2e/productcatalog_test.go (1)

284-286: Precision check for discount assertion.

Using InexactFloat64() to verify the 10% discount is acceptable for test assertions. However, if precise decimal validation is critical, consider verifying against an expected Decimal or confirm that float rounding is acceptable.

test/billing/adapter_test.go (1)

843-854: Helper function for discount lookup.

findAmountDiscountByDescription is a concise helper that clarifies test flow. Consider adding an inline comment or docstring explaining the fatal error for unrecognized descriptions to guide future maintainers.

openmeter/ent/db/billinginvoiceline_create.go (2)

838-853: Creating O2M edges for usage-based discounts.
This block updates the create specification to link multiple usage-based discount rows (O2M). If the goal is strictly one usage discount per line, consider adding an application or schema-level safeguard to ensure only one usage-based discount can be attached.


854-859: Creating O2M edges for amount-based discounts.
These lines set up the relationship for attaching multiples of amount-based discounts. If the PR’s objective includes enforcing a single discount per type, you might add validations or migrations to constrain it at the data or application layer.

openmeter/ent/db/billinginvoiceline_query.go (1)

566-586: Eager-loading usage & amount discounts
WithLineUsageDiscounts and WithLineAmountDiscounts enable precision in data fetching. Be mindful of performance when projects have large volumes of discount rows, as these joins may become intensive.

openmeter/ent/db/billinginvoicelineusagediscount_delete.go (2)

33-40: Error handling approach.
ExecX panics on error, which might be acceptable in CLI or testing contexts. In production code, consider capturing and returning errors.


84-88: ExecX panic pattern repeated.
Similar to previous comment about ExecX. Generally fine for tests or short-running tasks, though less ideal in robust production scenarios.

openmeter/ent/db/billinginvoicelineusagediscount_create.go (3)

193-200: SaveX panic usage.
Similar note as before: acceptable in testing or ephemeral contexts, but handle carefully in production code.


922-929: SaveX panic usage in bulk.
Consistent pattern with ent’s X methods for test or script usage.


1239-1244: ExecX in bulk.
Completes the pattern with a panic-on-error approach.

openmeter/ent/db/billinginvoicelineusagediscount_update.go (1)

216-370: Sufficient error handling with potential for concurrency checks.

The Save workflow, including error handling via NotFoundError and ConstraintError, aligns with Ent’s idiomatic patterns. If concurrent updates are a concern, consider adding optimistic concurrency fields (e.g., a version/timestamp) or enabling advanced locking strategies. Otherwise, this block appears correct and maintainable.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7951efc and 31123fb.

⛔ Files ignored due to path filters (1)
  • tools/migrate/migrations/atlas.sum is excluded by !**/*.sum
📒 Files selected for processing (96)
  • api/client/javascript/src/client/schemas.ts (20 hunks)
  • api/convert.gen.go (0 hunks)
  • api/openapi.cloud.yaml (19 hunks)
  • api/openapi.yaml (20 hunks)
  • api/spec/src/billing/invoices/discounts.tsp (4 hunks)
  • api/spec/src/billing/invoices/invoice.tsp (3 hunks)
  • api/spec/src/productcatalog/discounts.tsp (1 hunks)
  • api/spec/src/productcatalog/ratecards.tsp (2 hunks)
  • api/spec/src/productcatalog/subscription.tsp (2 hunks)
  • e2e/productcatalog_test.go (4 hunks)
  • openmeter/app/stripe/entity/app/invoice.go (2 hunks)
  • openmeter/billing/adapter/invoicelinediff.go (2 hunks)
  • openmeter/billing/adapter/invoicelinediff_test.go (16 hunks)
  • openmeter/billing/adapter/invoicelinemapper.go (2 hunks)
  • openmeter/billing/adapter/invoicelineprogressive.go (2 hunks)
  • openmeter/billing/adapter/invoicelines.go (5 hunks)
  • openmeter/billing/app.go (1 hunks)
  • openmeter/billing/discount.go (4 hunks)
  • openmeter/billing/httpdriver/deprecations.go (2 hunks)
  • openmeter/billing/httpdriver/discounts.go (1 hunks)
  • openmeter/billing/httpdriver/invoiceline.go (1 hunks)
  • openmeter/billing/invoiceline.go (1 hunks)
  • openmeter/billing/invoicelinediscount.go (9 hunks)
  • openmeter/billing/service/discounts.go (1 hunks)
  • openmeter/billing/service/lineservice/discountpercentage.go (3 hunks)
  • openmeter/billing/service/lineservice/feeline.go (3 hunks)
  • openmeter/billing/service/lineservice/feeline_test.go (2 hunks)
  • openmeter/billing/service/lineservice/pricedynamic_test.go (1 hunks)
  • openmeter/billing/service/lineservice/pricegraduatedtiered_test.go (1 hunks)
  • openmeter/billing/service/lineservice/pricepackage_test.go (1 hunks)
  • openmeter/billing/service/lineservice/priceunit_test.go (3 hunks)
  • openmeter/billing/service/lineservice/pricevolumetiered_test.go (1 hunks)
  • openmeter/billing/service/lineservice/usagebasedline.go (2 hunks)
  • openmeter/billing/service/lineservice/usagebasedline_test.go (5 hunks)
  • openmeter/ent/db/addonratecard_create.go (1 hunks)
  • openmeter/ent/db/addonratecard_update.go (2 hunks)
  • openmeter/ent/db/billinginvoicediscount.go (0 hunks)
  • openmeter/ent/db/billinginvoicediscount/billinginvoicediscount.go (0 hunks)
  • openmeter/ent/db/billinginvoicediscount/where.go (0 hunks)
  • openmeter/ent/db/billinginvoicediscount_create.go (0 hunks)
  • openmeter/ent/db/billinginvoicediscount_delete.go (0 hunks)
  • openmeter/ent/db/billinginvoicediscount_query.go (0 hunks)
  • openmeter/ent/db/billinginvoicediscount_update.go (0 hunks)
  • openmeter/ent/db/billinginvoiceline.go (6 hunks)
  • openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (4 hunks)
  • openmeter/ent/db/billinginvoiceline/where.go (1 hunks)
  • openmeter/ent/db/billinginvoiceline_create.go (3 hunks)
  • openmeter/ent/db/billinginvoiceline_query.go (10 hunks)
  • openmeter/ent/db/billinginvoiceline_update.go (9 hunks)
  • openmeter/ent/db/billinginvoicelinediscount.go (5 hunks)
  • openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (6 hunks)
  • openmeter/ent/db/billinginvoicelinediscount/where.go (4 hunks)
  • openmeter/ent/db/billinginvoicelinediscount_create.go (12 hunks)
  • openmeter/ent/db/billinginvoicelinediscount_update.go (8 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount.go (1 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (1 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount/where.go (1 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount_create.go (1 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount_delete.go (1 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount_query.go (1 hunks)
  • openmeter/ent/db/billinginvoicelineusagediscount_update.go (1 hunks)
  • openmeter/ent/db/client.go (11 hunks)
  • openmeter/ent/db/ent.go (2 hunks)
  • openmeter/ent/db/expose.go (1 hunks)
  • openmeter/ent/db/hook/hook.go (1 hunks)
  • openmeter/ent/db/migrate/schema.go (5 hunks)
  • openmeter/ent/db/paginate.go (5 hunks)
  • openmeter/ent/db/planratecard_create.go (1 hunks)
  • openmeter/ent/db/planratecard_update.go (2 hunks)
  • openmeter/ent/db/predicate/predicate.go (1 hunks)
  • openmeter/ent/db/runtime.go (2 hunks)
  • openmeter/ent/db/setorclear.go (3 hunks)
  • openmeter/ent/db/subscriptionitem_create.go (1 hunks)
  • openmeter/ent/db/subscriptionitem_update.go (2 hunks)
  • openmeter/ent/db/tx.go (2 hunks)
  • openmeter/ent/schema/billing.go (6 hunks)
  • openmeter/ent/schema/productcatalog.go (0 hunks)
  • openmeter/productcatalog/addon/ratecard_test.go (1 hunks)
  • openmeter/productcatalog/discount.go (3 hunks)
  • openmeter/productcatalog/discount_test.go (3 hunks)
  • openmeter/productcatalog/http/mapping.go (5 hunks)
  • openmeter/productcatalog/plan/ratecard_test.go (1 hunks)
  • openmeter/productcatalog/ratecard.go (4 hunks)
  • openmeter/productcatalog/ratecard_test.go (9 hunks)
  • openmeter/productcatalog/subscription/http/mapping.go (1 hunks)
  • openmeter/productcatalog/subscription/service/plan_test.go (1 hunks)
  • openmeter/subscription/repo/mapping.go (1 hunks)
  • openmeter/subscription/repo/subscriptionitemrepo.go (1 hunks)
  • openmeter/subscription/testutils/ratecard.go (1 hunks)
  • pkg/models/model.go (1 hunks)
  • test/app/stripe/invoice_test.go (1 hunks)
  • test/billing/adapter_test.go (3 hunks)
  • test/billing/discount_test.go (4 hunks)
  • test/billing/invoice_test.go (8 hunks)
  • tools/migrate/migrations/20250411062903_billing-split-line-discounts.down.sql (1 hunks)
  • tools/migrate/migrations/20250411062903_billing-split-line-discounts.up.sql (1 hunks)
💤 Files with no reviewable changes (9)
  • openmeter/ent/schema/productcatalog.go
  • openmeter/ent/db/billinginvoicediscount/where.go
  • openmeter/ent/db/billinginvoicediscount_delete.go
  • openmeter/ent/db/billinginvoicediscount_update.go
  • api/convert.gen.go
  • openmeter/ent/db/billinginvoicediscount_query.go
  • openmeter/ent/db/billinginvoicediscount_create.go
  • openmeter/ent/db/billinginvoicediscount.go
  • openmeter/ent/db/billinginvoicediscount/billinginvoicediscount.go
🚧 Files skipped from review as they are similar to previous changes (40)
  • openmeter/billing/service/lineservice/pricevolumetiered_test.go
  • openmeter/subscription/repo/mapping.go
  • openmeter/ent/db/planratecard_create.go
  • openmeter/billing/invoiceline.go
  • openmeter/subscription/repo/subscriptionitemrepo.go
  • openmeter/productcatalog/plan/ratecard_test.go
  • test/billing/discount_test.go
  • openmeter/ent/db/addonratecard_create.go
  • api/spec/src/productcatalog/subscription.tsp
  • openmeter/ent/db/subscriptionitem_create.go
  • openmeter/billing/adapter/invoicelineprogressive.go
  • openmeter/productcatalog/addon/ratecard_test.go
  • openmeter/ent/db/tx.go
  • openmeter/ent/db/planratecard_update.go
  • openmeter/ent/db/expose.go
  • openmeter/productcatalog/subscription/http/mapping.go
  • api/spec/src/productcatalog/discounts.tsp
  • api/spec/src/productcatalog/ratecards.tsp
  • openmeter/productcatalog/subscription/service/plan_test.go
  • openmeter/app/stripe/entity/app/invoice.go
  • pkg/models/model.go
  • openmeter/ent/db/subscriptionitem_update.go
  • openmeter/billing/service/lineservice/pricepackage_test.go
  • openmeter/subscription/testutils/ratecard.go
  • openmeter/productcatalog/ratecard_test.go
  • openmeter/billing/httpdriver/deprecations.go
  • openmeter/productcatalog/ratecard.go
  • openmeter/ent/db/ent.go
  • openmeter/billing/service/lineservice/usagebasedline.go
  • api/spec/src/billing/invoices/invoice.tsp
  • openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go
  • openmeter/billing/service/lineservice/discountpercentage.go
  • openmeter/ent/db/addonratecard_update.go
  • openmeter/billing/adapter/invoicelines.go
  • test/billing/invoice_test.go
  • openmeter/billing/service/lineservice/usagebasedline_test.go
  • openmeter/ent/db/billinginvoicelinediscount.go
  • openmeter/ent/db/billinginvoicelineusagediscount.go
  • tools/migrate/migrations/20250411062903_billing-split-line-discounts.down.sql
  • tools/migrate/migrations/20250411062903_billing-split-line-discounts.up.sql
🧰 Additional context used
🧬 Code Graph Analysis (35)
test/app/stripe/invoice_test.go (7)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
api/api.gen.go (1)
  • Discounts (2020-2026)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
api/client/go/client.gen.go (1)
  • Discounts (1891-1897)
openmeter/ent/db/billinginvoiceline/where.go (2)
  • Amount (102-104)
  • Description (97-99)
openmeter/ent/db/billinginvoicelinediscount/where.go (2)
  • Amount (111-113)
  • Description (101-103)
openmeter/ent/db/billinginvoicelineusagediscount/where.go (1)
  • Description (101-103)
openmeter/ent/db/predicate/predicate.go (2)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/ent/schema/billing.go (5)
  • BillingInvoiceLineUsageDiscount (627-629)
  • BillingInvoiceLineUsageDiscount (631-638)
  • BillingInvoiceLineUsageDiscount (640-664)
  • BillingInvoiceLineUsageDiscount (666-675)
  • BillingInvoiceLineUsageDiscount (677-685)
e2e/productcatalog_test.go (4)
api/api.gen.go (3)
  • DiscountPercentage (1954-1957)
  • Percentage (4688-4688)
  • Discounts (2020-2026)
pkg/models/percentage.go (2)
  • Percentage (9-11)
  • NewPercentage (15-28)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
openmeter/billing/httpdriver/discounts.go (3)
openmeter/productcatalog/http/mapping.go (3)
  • AsDiscounts (523-545)
  • AsPercentageDiscount (558-562)
  • AsUsageDiscount (547-556)
api/api.gen.go (3)
  • BillingDiscounts (1089-1095)
  • Discounts (2020-2026)
  • Percentage (4688-4688)
openmeter/productcatalog/discount.go (3)
  • Discounts (113-116)
  • PercentageDiscount (21-24)
  • UsageDiscount (60-62)
openmeter/billing/service/discounts.go (3)
api/api.gen.go (2)
  • Percentage (4688-4688)
  • Discounts (2020-2026)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
test/billing/adapter_test.go (2)
openmeter/billing/discount.go (4)
  • Discounts (78-81)
  • NewDiscountReasonFrom (154-191)
  • MaximumSpendDiscount (145-145)
  • PercentageDiscount (24-28)
openmeter/billing/invoicelinediscount.go (4)
  • LineDiscounts (312-315)
  • AmountLineDiscountManaged (104-107)
  • AmountLineDiscount (56-64)
  • LineDiscountBase (22-27)
openmeter/billing/service/lineservice/pricegraduatedtiered_test.go (2)
openmeter/billing/discount.go (3)
  • Discounts (78-81)
  • NewDiscountReasonFrom (154-191)
  • MaximumSpendDiscount (145-145)
openmeter/billing/invoicelinediscount.go (5)
  • LineDiscounts (312-315)
  • AmountLineDiscountManaged (104-107)
  • AmountLineDiscount (56-64)
  • LineDiscountBase (22-27)
  • LineMaximumSpendReferenceID (19-19)
openmeter/billing/service/lineservice/feeline_test.go (3)
openmeter/billing/discount.go (2)
  • PercentageDiscount (24-28)
  • Discounts (78-81)
openmeter/productcatalog/discount.go (2)
  • PercentageDiscount (21-24)
  • Discounts (113-116)
openmeter/billing/invoicelinediscount.go (3)
  • LineDiscounts (312-315)
  • AmountLineDiscount (56-64)
  • LineDiscountBase (22-27)
openmeter/billing/adapter/invoicelinemapper.go (1)
openmeter/billing/invoicelinediscount.go (5)
  • UsageLineDiscountManaged (254-257)
  • LineDiscountBase (22-27)
  • UsageLineDiscount (205-210)
  • AmountLineDiscountManaged (104-107)
  • AmountLineDiscount (56-64)
api/client/javascript/src/client/schemas.ts (4)
api/api.gen.go (12)
  • BillingDiscountReason (1067-1069)
  • BillingDiscountUsage (1072-1086)
  • BillingDiscounts (1089-1095)
  • DiscountReasonMaximumSpend (1960-1962)
  • DiscountReasonRatecardPercentage (1968-1981)
  • DiscountReasonRatecardUsage (1987-2002)
  • DiscountUsage (2012-2017)
  • Discounts (2020-2026)
  • InvoiceLineAmountDiscount (3344-3368)
  • InvoiceLineAppExternalIds (3371-3377)
  • InvoiceLineDiscounts (3380-3390)
  • InvoiceLineUsageDiscount (3441-3470)
api/client/go/client.gen.go (12)
  • BillingDiscountReason (965-967)
  • BillingDiscountUsage (970-984)
  • BillingDiscounts (987-993)
  • DiscountReasonMaximumSpend (1831-1833)
  • DiscountReasonRatecardPercentage (1839-1852)
  • DiscountReasonRatecardUsage (1858-1873)
  • DiscountUsage (1883-1888)
  • Discounts (1891-1897)
  • InvoiceLineAmountDiscount (3093-3117)
  • InvoiceLineAppExternalIds (3120-3126)
  • InvoiceLineDiscounts (3129-3139)
  • InvoiceLineUsageDiscount (3190-3219)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
openmeter/productcatalog/discount_test.go (3)
openmeter/billing/discount.go (3)
  • Discounts (78-81)
  • PercentageDiscount (24-28)
  • UsageDiscount (49-53)
api/api.gen.go (2)
  • Discounts (2020-2026)
  • Percentage (4688-4688)
openmeter/productcatalog/discount.go (3)
  • Discounts (113-116)
  • PercentageDiscount (21-24)
  • UsageDiscount (60-62)
openmeter/ent/db/billinginvoiceline/where.go (4)
openmeter/ent/db/predicate/predicate.go (3)
  • BillingInvoiceLine (65-65)
  • BillingInvoiceLineUsageDiscount (93-93)
  • BillingInvoiceLineDiscount (79-79)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (5)
  • Table (105-105)
  • LineUsageDiscountsTable (136-136)
  • LineUsageDiscountsColumn (141-141)
  • LineAmountDiscountsTable (143-143)
  • LineAmountDiscountsColumn (148-148)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/ent/db/billinginvoicelinediscount.go (2)
  • BillingInvoiceLineDiscount (19-63)
  • BillingInvoiceLineDiscount (86-105)
openmeter/billing/adapter/invoicelinediff_test.go (4)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
openmeter/billing/invoicelinediscount.go (3)
  • AmountLineDiscountManaged (104-107)
  • LineDiscounts (312-315)
  • AmountLineDiscount (56-64)
pkg/models/model.go (1)
  • ManagedModelWithID (155-158)
openmeter/ent/db/billinginvoicelineusagediscount_query.go (6)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (6)
  • OrderOption (112-112)
  • Table (47-47)
  • FieldID (19-19)
  • BillingInvoiceLineColumn (54-54)
  • Label (17-17)
  • FieldLineID (29-29)
openmeter/ent/db/predicate/predicate.go (2)
  • BillingInvoiceLineUsageDiscount (93-93)
  • BillingInvoiceLine (65-65)
openmeter/ent/db/billinginvoiceline_query.go (1)
  • BillingInvoiceLineQuery (29-50)
openmeter/ent/db/client.go (1)
  • BillingInvoiceLineClient (2474-2476)
openmeter/ent/db/billinginvoiceline/where.go (2)
  • IDIn (32-34)
  • ID (17-19)
openmeter/ent/db/billinginvoicelineusagediscount/where.go (3)
  • LineID (91-93)
  • IDIn (31-33)
  • ID (16-18)
openmeter/billing/httpdriver/invoiceline.go (3)
openmeter/billing/invoicelinediscount.go (1)
  • LineDiscounts (312-315)
api/api.gen.go (6)
  • InvoiceLineDiscounts (3380-3390)
  • InvoiceLineAmountDiscount (3344-3368)
  • InvoiceLineAppExternalIds (3371-3377)
  • InvoiceLineUsageDiscount (3441-3470)
  • BillingDiscountReason (1067-1069)
  • Percentage (4688-4688)
openmeter/billing/discount.go (4)
  • DiscountReason (147-152)
  • MaximumSpendDiscountReason (131-131)
  • RatecardPercentageDiscountReason (132-132)
  • RatecardUsageDiscountReason (133-133)
openmeter/productcatalog/discount.go (9)
openmeter/billing/discount.go (1)
  • PercentageDiscount (24-28)
pkg/models/percentage.go (1)
  • Percentage (9-11)
openmeter/productcatalog/plan/adapter/adapter.go (1)
  • New (42-51)
pkg/models/error.go (1)
  • NewNillableGenericValidationError (129-135)
openmeter/billing/invoiceline.go (1)
  • Price (701-701)
openmeter/productcatalog/price.go (1)
  • Price (84-91)
pkg/equal/equal.go (1)
  • Equaler (9-11)
pkg/models/equaler.go (1)
  • Equaler (3-6)
pkg/models/clonable.go (1)
  • Clonable (3-5)
openmeter/productcatalog/http/mapping.go (5)
openmeter/billing/discount.go (1)
  • Discounts (78-81)
api/client/javascript/src/client/schemas.ts (4)
  • Discounts (9386-9386)
  • DiscountUsage (9385-9385)
  • Percentage (9616-9616)
  • DiscountPercentage (9378-9378)
api/api.gen.go (4)
  • Discounts (2020-2026)
  • DiscountUsage (2012-2017)
  • Percentage (4688-4688)
  • DiscountPercentage (1954-1957)
openmeter/productcatalog/discount.go (1)
  • Discounts (113-116)
api/client/go/client.gen.go (4)
  • Discounts (1891-1897)
  • DiscountUsage (1883-1888)
  • Percentage (4384-4384)
  • DiscountPercentage (1825-1828)
openmeter/ent/db/billinginvoiceline_query.go (4)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (1)
  • OrderOption (285-285)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (1)
  • OrderOption (123-123)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (1)
  • OrderOption (112-112)
openmeter/ent/db/billinginvoicelineusagediscount_query.go (1)
  • BillingInvoiceLineUsageDiscountQuery (21-32)
openmeter/ent/db/billinginvoiceline.go (4)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/ent/db/billinginvoicelinediscount.go (2)
  • BillingInvoiceLineDiscount (19-63)
  • BillingInvoiceLineDiscount (86-105)
openmeter/ent/db/billinginvoicelineusagediscount_query.go (1)
  • BillingInvoiceLineUsageDiscountQuery (21-32)
openmeter/ent/db/billinginvoicelinediscount_query.go (1)
  • BillingInvoiceLineDiscountQuery (21-32)
openmeter/ent/db/runtime.go (1)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (1)
  • ValueScanner (96-98)
openmeter/ent/db/billinginvoiceline_create.go (3)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (6)
  • Table (105-105)
  • LineUsageDiscountsTable (136-136)
  • LineUsageDiscountsColumn (141-141)
  • FieldID (19-19)
  • LineAmountDiscountsTable (143-143)
  • LineAmountDiscountsColumn (148-148)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (2)
  • Table (53-53)
  • FieldID (19-19)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (2)
  • Table (47-47)
  • FieldID (19-19)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (2)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (3)
  • OrderOption (123-123)
  • Table (53-53)
  • FieldID (19-19)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (3)
  • OrderOption (112-112)
  • Table (47-47)
  • FieldID (19-19)
openmeter/ent/schema/billing.go (3)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/ent/db/billinginvoicelinediscount.go (2)
  • BillingInvoiceLineDiscount (19-63)
  • BillingInvoiceLineDiscount (86-105)
openmeter/ent/db/billinginvoiceline.go (2)
  • BillingInvoiceLine (27-103)
  • BillingInvoiceLine (237-262)
openmeter/ent/db/billinginvoicelineusagediscount_delete.go (4)
openmeter/ent/db/ent.go (3)
  • IsConstraintError (361-367)
  • ConstraintError (345-348)
  • NotFoundError (278-280)
openmeter/ent/db/mutation.go (1)
  • BillingInvoiceLineUsageDiscountMutation (18699-18721)
openmeter/ent/db/predicate/predicate.go (1)
  • BillingInvoiceLineUsageDiscount (93-93)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (3)
  • Table (47-47)
  • FieldID (19-19)
  • Label (17-17)
openmeter/ent/db/billinginvoicelinediscount_update.go (1)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (5)
  • FieldReason (35-35)
  • FieldInvoicingAppExternalID (37-37)
  • FieldType (45-45)
  • FieldQuantity (47-47)
  • FieldPreLinePeriodQuantity (49-49)
openmeter/ent/db/billinginvoiceline_update.go (2)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (1)
  • FieldID (19-19)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (1)
  • FieldID (19-19)
openmeter/ent/db/migrate/schema.go (3)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (2)
  • Columns (173-206)
  • Table (105-105)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (2)
  • Columns (64-78)
  • Table (53-53)
openmeter/ent/db/billinginvoice/billinginvoice.go (2)
  • Columns (202-257)
  • Table (142-142)
openmeter/ent/db/billinginvoicelinediscount_create.go (5)
openmeter/billing/discount.go (3)
  • DiscountReasonType (128-128)
  • DiscountReasonType (136-142)
  • DiscountReason (147-152)
openmeter/billing/invoiceline.go (1)
  • LineID (20-20)
openmeter/ent/db/ent.go (1)
  • ValidationError (253-256)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (7)
  • FieldReason (35-35)
  • FieldInvoicingAppExternalID (37-37)
  • FieldAmount (39-39)
  • FieldType (45-45)
  • FieldQuantity (47-47)
  • FieldPreLinePeriodQuantity (49-49)
  • FieldSourceDiscount (43-43)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (4)
  • FieldInvoicingAppExternalID (73-73)
  • FieldAmount (35-35)
  • FieldType (61-61)
  • FieldQuantity (67-67)
openmeter/ent/db/setorclear.go (3)
openmeter/ent/db/billinginvoicelinediscount_update.go (2)
  • BillingInvoiceLineDiscountUpdate (22-26)
  • BillingInvoiceLineDiscountUpdateOne (451-456)
openmeter/billing/discount.go (1)
  • DiscountReason (147-152)
openmeter/ent/db/billinginvoicelineusagediscount_update.go (2)
  • BillingInvoiceLineUsageDiscountUpdate (22-26)
  • BillingInvoiceLineUsageDiscountUpdateOne (373-378)
openmeter/billing/invoicelinediscount.go (7)
openmeter/billing/invoiceline.go (1)
  • LineExternalIDs (235-237)
openmeter/billing/discount.go (1)
  • DiscountReason (147-152)
pkg/models/validator.go (1)
  • Validate (16-26)
pkg/models/model.go (2)
  • ManagedModelWithID (155-158)
  • ManagedModel (107-113)
pkg/models/clonable.go (1)
  • Clonable (3-5)
pkg/models/error.go (1)
  • NewNillableGenericValidationError (129-135)
pkg/slicesx/map.go (1)
  • MapWithErr (23-47)
openmeter/ent/db/client.go (2)
openmeter/ent/db/billinginvoicelineusagediscount_query.go (1)
  • BillingInvoiceLineUsageDiscountQuery (21-32)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (4)
  • Table (105-105)
  • FieldID (19-19)
  • LineUsageDiscountsTable (136-136)
  • LineUsageDiscountsColumn (141-141)
openmeter/ent/db/billinginvoicelineusagediscount_create.go (4)
openmeter/ent/db/mutation.go (1)
  • BillingInvoiceLineUsageDiscountMutation (18699-18721)
openmeter/billing/discount.go (3)
  • DiscountReasonType (128-128)
  • DiscountReasonType (136-142)
  • DiscountReason (147-152)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/billing/invoiceline.go (1)
  • LineID (20-20)
openmeter/ent/db/billinginvoicelinediscount/where.go (5)
openmeter/ent/db/predicate/predicate.go (1)
  • BillingInvoiceLineDiscount (79-79)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (2)
  • FieldInvoicingAppExternalID (73-73)
  • FieldType (61-61)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (4)
  • FieldInvoicingAppExternalID (37-37)
  • FieldType (45-45)
  • FieldReason (35-35)
  • FieldSourceDiscount (43-43)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (2)
  • FieldInvoicingAppExternalID (37-37)
  • FieldReason (35-35)
openmeter/billing/discount.go (2)
  • DiscountReasonType (128-128)
  • DiscountReasonType (136-142)
openmeter/ent/db/billinginvoicelineusagediscount_update.go (4)
openmeter/ent/db/mutation.go (1)
  • BillingInvoiceLineUsageDiscountMutation (18699-18721)
openmeter/ent/db/predicate/predicate.go (2)
  • BillingInvoiceLineUsageDiscount (93-93)
  • BillingInvoiceLine (65-65)
openmeter/ent/db/billinginvoicelineusagediscount/where.go (8)
  • ID (16-18)
  • UpdatedAt (81-83)
  • DeletedAt (86-88)
  • ChildUniqueReferenceID (96-98)
  • Description (101-103)
  • InvoicingAppExternalID (106-108)
  • Quantity (111-113)
  • PreLinePeriodQuantity (116-118)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (13)
  • UpdateDefaultUpdatedAt (92-92)
  • ReasonValidator (102-109)
  • Columns (58-72)
  • FieldID (19-19)
  • FieldUpdatedAt (25-25)
  • FieldDeletedAt (27-27)
  • FieldChildUniqueReferenceID (31-31)
  • FieldDescription (33-33)
  • FieldReason (35-35)
  • FieldInvoicingAppExternalID (37-37)
  • FieldQuantity (39-39)
  • FieldPreLinePeriodQuantity (41-41)
  • FieldReasonDetails (43-43)
openmeter/ent/db/billinginvoicelineusagediscount/where.go (7)
openmeter/ent/db/billinginvoicelineusagediscount.go (2)
  • BillingInvoiceLineUsageDiscount (19-51)
  • BillingInvoiceLineUsageDiscount (74-93)
openmeter/ent/db/predicate/predicate.go (2)
  • BillingInvoiceLineUsageDiscount (93-93)
  • BillingInvoiceLine (65-65)
openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (9)
  • FieldID (19-19)
  • FieldNamespace (21-21)
  • FieldCreatedAt (25-25)
  • FieldUpdatedAt (27-27)
  • FieldDeletedAt (29-29)
  • FieldChildUniqueReferenceID (75-75)
  • FieldDescription (33-33)
  • FieldInvoicingAppExternalID (73-73)
  • FieldQuantity (67-67)
openmeter/ent/db/billinginvoicelinediscount/billinginvoicelinediscount.go (11)
  • FieldID (19-19)
  • FieldNamespace (21-21)
  • FieldCreatedAt (23-23)
  • FieldUpdatedAt (25-25)
  • FieldDeletedAt (27-27)
  • FieldLineID (29-29)
  • FieldChildUniqueReferenceID (31-31)
  • FieldDescription (33-33)
  • FieldInvoicingAppExternalID (37-37)
  • FieldQuantity (47-47)
  • FieldReason (35-35)
openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (11)
  • FieldID (19-19)
  • FieldNamespace (21-21)
  • FieldCreatedAt (23-23)
  • FieldUpdatedAt (25-25)
  • FieldDeletedAt (27-27)
  • FieldLineID (29-29)
  • FieldChildUniqueReferenceID (31-31)
  • FieldDescription (33-33)
  • FieldInvoicingAppExternalID (37-37)
  • FieldQuantity (39-39)
  • FieldReason (35-35)
openmeter/billing/invoiceline.go (1)
  • LineID (20-20)
openmeter/billing/discount.go (2)
  • DiscountReasonType (128-128)
  • DiscountReasonType (136-142)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: Test
  • GitHub Check: Lint
  • GitHub Check: E2E
  • GitHub Check: Developer environment
  • GitHub Check: CI
  • GitHub Check: Commit hooks
  • GitHub Check: Analyze (go)
🔇 Additional comments (349)
openmeter/ent/db/billinginvoiceline/where.go (2)

1896-1917: New edge functions properly implement the usage discounts relation.

The implementation correctly adds predicates for querying line_usage_discounts relationships, following the architectural change to separate unit and amount discounts into different tables as mentioned in the PR objectives.


1919-1940: New edge functions properly implement the amount discounts relation.

The implementation correctly adds predicates for the line_amount_discounts relationship, maintaining consistent naming patterns and implementation style with the rest of the codebase. These functions enable the new discount structure that allows only a single discount per type.

openmeter/ent/db/migrate/schema.go (7)

777-777: Appropriate enum value update for the discount refactoring.

The reason field's enum values have been updated to include ratecard_percentage and ratecard_usage, replacing the previous single value ratecard_discount. This change properly supports the new discount structure that allows for a single discount per type.


778-782: Good addition of fields to support the new discount model.

The addition of invoicing_app_external_id, source_discount, and type fields provides necessary information for the new discount structure. The source_discount field being a JSON type allows storing the complete discount information which is important for tracking the origin of calculated discounts.


794-794: Foreign key name updated to reflect amount-specific discounts.

The foreign key symbol has been updated to billing_invoice_line_discounts_billing_invoice_lines_line_amount_discounts, which clearly indicates that this table now specifically handles amount-based discounts as part of the separation of discount types.


826-841: Well-structured schema for new usage-based discounts table.

Creating a separate table for usage-based discounts is a good design decision as it allows for more precise management of null and non-null flags within the database. The table structure properly includes all necessary fields to track usage-based discounts with appropriate types and constraints.


842-875: Well-defined table configuration for usage-based discounts.

The table definition includes appropriate primary key, foreign key relationships to the invoice lines table, and well-thought-out indexes to ensure efficient querying. The index on namespace_line_id_child_unique_reference_id with the non-null constraint is particularly important for data integrity.


2308-2308: New usage discounts table properly added to schema tables list.

The BillingInvoiceLineUsageDiscountsTable has been correctly added to the Tables slice, ensuring it will be properly handled during schema migrations and database operations.


2365-2365: Foreign key reference properly set for new table.

The foreign key relationship for BillingInvoiceLineUsageDiscountsTable is correctly initialized to reference the BillingInvoiceLinesTable, establishing the proper parent-child relationship between invoice lines and their usage-based discounts.

openmeter/ent/db/billinginvoicelinediscount_create.go (9)

111-115: Method signature updated for SetReason

The SetReason method has been modified to accept billing.DiscountReasonType instead of the previous type, aligning with the new discount structure that supports a single discount per type. This change is consistent with the PR objectives.


117-129: New methods for invoicing app external ID handling

These new methods for managing the invoicing_app_external_id field support integration with external invoicing systems. The addition of both required and nullable versions provides good flexibility for different usage scenarios.


131-135: Addition of required SetAmount method

The SetAmount method has been added as a required field (no nullable version), which aligns with the PR's goal of restructuring the discount representation. Making amount a required field ensures that all discounts have a properly defined value.


151-155: New SetSourceDiscount method added

This method enables linking discounts to their source through the billing.DiscountReason type. This supports the new discount structure mentioned in the PR objectives, allowing for more detailed tracking of discount origins.


157-169: Type field handling updated

The SetType and SetNillableType methods now accept string values instead of a specific enum type. This change provides more flexibility in how discount types can be defined while maintaining the PR's goal of refactoring the discount structure.


289-302: Validation logic updated for required fields

The validation logic in the check method has been appropriately updated to:

  1. Ensure line_id is required
  2. Ensure amount is required

These validation changes are consistent with the new discount structure, enforcing required fields while allowing flexibility for optional ones.


374-409: Updated field mapping in createSpec

The createSpec method has been properly updated to handle all the modified and new fields:

  • Reason with the new type
  • InvoicingAppExternalID as an optional field
  • Amount as a required field
  • Type, Quantity, and PreLinePeriodQuantity with proper type handling

This ensures that all database fields are correctly populated when creating new discount records.


557-686: Comprehensive upsert methods for all fields

A complete set of upsert methods has been implemented for all the modified and new fields, maintaining consistency with the create methods. This ensures that all operations (create, update, upsert) have the same capability and behavior when working with discount records.


1303-1454: Bulk upsert operations properly supported

All the changes have been consistently applied to the bulk upsert operations as well, ensuring that both individual and batch processing use the same field types and validation rules. This maintains consistency throughout the API surface.

openmeter/ent/db/billinginvoicelinediscount_update.go (6)

114-126: Great use of typed enums for reason.

The transition to billing.DiscountReasonType and the associated validators ensures stronger type safety. This helps mitigate errors and clarifies the purpose of the field.


182-192: source_discount addition looks good.

The pattern of setting and clearing source_discount aligns with Ent’s approach. Make sure the field is non-sensitive or properly masked if it may contain user data.


363-408: Field assignment in sqlSave aligns with the updated schema.

The logic updates each field with the correct field.Type* based on your changes. This is in sync with the new approach for reason, invoicing_app_external_id, type, quantity, and pre_line_period_quantity. Ensure any migrations cover the new data types properly in production.

Would you like to verify the related migration scripts to confirm they align with these field changes?


538-550: SetReason methods for UpdateOne are aligned with the main builder.

Keeping these methods parallel to the multi-entity update builder is a good practice and helps maintain consistency across update paths.


606-616: SetSourceDiscount is properly mirrored in UpdateOne.

The pointer-based approach with a validator is consistent. This helps ensure that only valid discount values enter the database.


817-862: sqlSave for UpdateOne correctly uses the new fields.

All newly added fields (reason, invoicing_app_external_id, type, quantity, etc.) are persisted in alignment with the multi-update logic. The hooking into check() ensures they pass custom validators before final storage.

test/app/stripe/invoice_test.go (1)

561-565: Updated loop to match new discount structure

The code now iterates over line.Discounts.Amount array instead of the previous generic line.Discounts structure, and uses lo.FromPtrOr to safely handle potential nil descriptions. This change aligns with the new discount model that separates amount and usage discounts.

openmeter/billing/service/lineservice/pricedynamic_test.go (1)

188-201: Refactored discount structure in test

The test case now uses the new LineDiscounts structure with an Amount slice of AmountLineDiscountManaged objects, replacing the previous flat discount approach. This correctly reflects the refactored discount model that separates different discount types. The reason is also properly constructed using NewDiscountReasonFrom.

openmeter/billing/app.go (1)

219-228: Updated discount handling to use new structure

The merge process now correctly processes amount and usage discounts as separate collections, iterating over line.Discounts.Amount and line.Discounts.Usage respectively. This change properly supports the new discount model that allows for single discount per type while maintaining the external ID assignment logic.

openmeter/billing/httpdriver/discounts.go (1)

34-62: Redesigned AsDiscounts function for new discount structure

The function signature has been updated to accept a pointer to api.BillingDiscounts instead of a slice of api.BillingDiscount, reflecting the new model that separates discount types. The implementation now:

  1. Handles nil input safely
  2. Processes percentage and usage discounts separately when present
  3. Maintains error handling for usage discount conversion

This change correctly implements the new discount model while providing backward compatibility through proper nil checking.

openmeter/ent/db/predicate/predicate.go (1)

92-104: New predicate type for BillingInvoiceLineUsageDiscount added correctly.

This new predicate type and its error-handling function follow the established pattern in the codebase. The BillingInvoiceLineUsageDiscount predicate will be used with the SQL selector in query builders, and the error handling function properly checks for nil errors before executing the predicate.

openmeter/ent/db/runtime.go (1)

504-533: Schema initialization for BillingInvoiceLineUsageDiscount is properly configured.

The initialization code properly sets up the validators, defaults, and value scanners for the new entity type. The implementation follows the same pattern as other entities in the file, ensuring consistency throughout the codebase.

openmeter/billing/service/lineservice/feeline.go (2)

41-71: Updated to handle single discount per type instead of multiple discounts.

The implementation has been refactored to align with the new discount structure that allows only a single discount per type. The function now retrieves a single discount object rather than a collection, simplifying the discount handling logic.

Points to note:

  • Line 44: Now gets a single discount rather than a collection
  • Line 49: Condition checks for nil discount rather than empty collection
  • Line 65: Uses a single discount for calculation
  • Line 70: Appends to the Amount field of l.line.Discounts

84-85: Totals calculation updated to match new discount structure.

The DiscountsTotal calculation has been updated to sum the Amount field of the Discounts structure, which matches the new data model where discounts are consolidated by type.

openmeter/billing/service/discounts.go (2)

11-29: Simplified discount correlation ID generation.

The function has been refactored to be more straightforward, directly checking if each discount type is present and then generating or validating its correlation ID. This approach is cleaner and more maintainable than the previous implementation.


31-42: Well-designed helper function for correlation ID generation.

The new generateCorrelationID function encapsulates the logic for either generating a new correlation ID or validating an existing one. This reduces code duplication and improves maintainability.

The function properly:

  1. Generates a new ULID if no correlation ID is provided
  2. Validates existing correlation IDs to ensure they're valid ULIDs
  3. Returns descriptive errors for invalid IDs
openmeter/ent/db/hook/hook.go (1)

168-178: Addition of BillingInvoiceLineUsageDiscountFunc supports the discount structure refactoring.

This new hook function accommodates the separation of unit and amount discounts into different tables, which aligns with the PR objective of modifying the discount structure. This change allows more precise management of null and non-null flags within the database.

openmeter/billing/service/lineservice/pricegraduatedtiered_test.go (1)

258-292: Updated discount structure implementation enhances clarity and organization.

The test code has been updated to use the new LineDiscounts structure which provides better organization by separating amount and usage-based discounts. The previous approach likely used a simpler structure, but this change allows for more precise discount management, aligning with the PR objective to allow single discount per type.

openmeter/billing/adapter/invoicelinemapper.go (4)

163-163: Safe default initialization of RateCardDiscounts.

Changed from potentially returning nil to returning an empty billing.Discounts{} object, which prevents nil pointer errors when accessing this field later in the code.


213-228: Improved discount handling with type-specific processing.

The discount handling has been refactored to separate usage-based and amount-based discounts, with proper error handling for each type. This supports the PR objective of splitting discount types into different tables, providing better organization and error reporting.


233-269: New mapping function for usage-based discounts.

This function handles the conversion from database model to domain model for invoice line usage discounts, with special handling for legacy maximum spend discounts. The error handling for missing reason details ensures data integrity.


271-307: New mapping function for amount-based discounts.

This function handles the conversion from database model to domain model for invoice line amount discounts, with special handling for legacy discounts. The error handling for missing source discount details ensures data integrity during the transition to the new structure.

openmeter/billing/httpdriver/invoiceline.go (1)

492-532: New function to handle discount reason mapping to API format.

This function properly handles the conversion of various discount reason types to their API representations, with appropriate error handling for unknown types. This ensures consistent representation of discount reasons across the API.

openmeter/billing/service/lineservice/feeline_test.go (3)

22-27: Updated discount structure to use a single rate card discount

The code now uses a single RateCardDiscount of type billing.PercentageDiscount instead of an array of discounts, which aligns with the PR objective to permit only a single discount per type.


32-48: Updated expected JSON structure to use the new discount model

The expected JSON comparison has been updated to use the new LineDiscounts structure with properly nested Amount array of AmountLineDiscountManaged objects. This is consistent with the unified discount handling approach.


69-71: Updated line base to use the new Discounts structure

The RateCardDiscounts field in LineBase now uses the new billing.Discounts structure with a pointer to the cloned discount, which matches the PR objective of restructuring discounts.

openmeter/billing/service/lineservice/priceunit_test.go (4)

188-201: Updated discount structure for maximum spend discount

The code now uses the new LineDiscounts structure with properly nested Amount array for the maximum spend discount calculation. This ensures consistency with the new discount model.


209-214: Simplified percentage discount initialization

The discount is now initialized directly as a struct rather than through a function call, making the code more explicit about the discount structure. The inclusion of a CorrelationID field also improves traceability of discounts.


233-235: Updated discount assignment to use the new Discounts structure

The code now uses billing.Discounts with a Percentage field pointing to the discount object, aligning with the PR objective of having a single discount per type.


249-271: Updated expected discounts structure for combined discount scenario

The test case for combined discounts (percentage + maximum spend) now uses the new LineDiscounts structure with an Amount array. This properly represents the case where multiple amount discounts can still be applied while maintaining the single-discount-per-type model.

openmeter/billing/adapter/invoicelinediff_test.go (21)

3-5: Added appropriate imports

The code now imports the fmt package for string formatting and the models package which contains the ManagedModelWithID struct used in the refactored discount structure.

Also applies to: 13-14


23-23: Renamed discount field to be more specific

The field has been renamed from Discounts to AmountDiscounts to clearly indicate it's specifically for amount-based discounts rather than generic discounts, improving code clarity.


51-51: Updated discount initialization for test case

Updated to use newAmountDiscountsWithIDs instead of the previous function to initialize discounts, which aligns with the new discount structure.


87-89: Updated field reference to match the renamed field

Field reference has been updated from Discounts to AmountDiscounts to maintain consistency with the struct field renaming.


121-124: Updated field reference in child diff expectation

Field reference has been updated from Discounts to AmountDiscounts in the child diff expectation test case for deletion scenarios.


179-179: Updated discount access pattern

Now accessing discount ID through the new structure with .Discounts.Amount[0].ID, which reflects the new nested discount organization.


194-198: Updated field reference for create/delete diff expectations

Field reference has been updated from Discounts to AmountDiscounts in the test case expectations for when discounts are both created and deleted.


208-208: Updated discount clearing pattern

Now setting Discounts.Amount = nil instead of clearing the old direct discounts array, reflecting the new structure where amount discounts are in a specific field.


216-218: Updated field reference for discount deletion test

Field reference has been updated from Discounts to AmountDiscounts in the test case for discount deletion.


227-227: Updated discount amount access pattern

Now accessing discount amount through the new structure with .Discounts.Amount[0].Amount, matching the new nested organization.


235-237: Updated field reference for discount update test

Field reference has been updated from Discounts to AmountDiscounts in the test case for discount updates.


246-249: Updated discount access and modification

Now accessing discounts via .Discounts.Amount and modifying fields on the discount objects directly, which aligns with the new structure.


257-260: Updated field reference for discount create/delete test

Field reference has been updated from Discounts to AmountDiscounts in the test expectations for creating and deleting discounts.


281-283: Updated field reference for deletion with deletedAt

Field reference has been updated from Discounts to AmountDiscounts in the test case for deleting items using the deletedAt field.


305-307: Updated field reference for parent deletion test

Field reference has been updated from Discounts to AmountDiscounts in the test case where a parent line with children is deleted.


384-392: Updated discount mapping function to use specific type

Function now explicitly works with AmountLineDiscountManaged type instead of a generic discount type, which improves type safety and code clarity.


394-394: Updated diff mapping function to use specific type

Function signature now explicitly uses AmountLineDiscountManaged type, which aligns with the more specific discount handling approach.


402-413: Added helper function for error message formatting

Added a new msgPrefix utility function that enhances error message formatting by properly prefixing messages, which improves test failure diagnostics.


418-420: Updated error message formatting for diff comparisons

Now using the new msgPrefix function to generate better formatted error messages when diffs don't match expectations.


430-430: Updated diff verification to use specific discount type

Changed to use AmountDiscounts and mapLineDiscountDiffToIDs function for comparing discount diffs, which aligns with the renamed fields and functions.


472-485: Reimplemented discount creation function for new structure

The newAmountDiscountsWithIDs function now creates a LineDiscounts structure with an Amount field containing AmountLineDiscountManaged objects. This properly implements the new discount model where discounts are organized by type.

api/openapi.yaml (13)

12151-12173: Enhanced "DiscountPercentage" and "DiscountReasonMaximumSpend" Schemas.
The DiscountPercentage schema now enforces a required percentage bounded between 0 and 100, and the DiscountReasonMaximumSpend schema defines a clear enum value. Both changes improve schema strictness and consistency.


12234-12241: "DiscountUsage" Schema Definition.
The newly added DiscountUsage schema minimally requires a numeric quantity. Confirm that downstream billing logic correctly interprets this value for usage-based discounts.


14723-14727: "InvoiceFlatFeeRateCard" Discounts Reference Update.
The discounts field now references BillingDiscounts, which aligns with the refactored discount model. Please confirm that flat fee implementations enforce the intended constraint (e.g. only percentage discounts, if that is the underlying business logic).


14763-14773: Addition of "InvoiceLineAmountDiscount" Schema.
This hunk introduces the InvoiceLineAmountDiscount schema with required fields such as createdAt, updatedAt, id, reason, and amount. The schema appears well-defined; please verify that invoice line calculations are updated to utilize this new schema.


14798-14803: "reason" Property Now References the New Discount Schema.
Changing the reason property to reference BillingDiscountReason enhances consistency across discount definitions.


14937-15005: Robust Definition of "InvoiceLineUsageDiscount" Schema.
This new schema includes detailed metadata (timestamps, IDs, correlation, and descriptive fields) for usage-based discounts. It is well-documented—please double-check that the semantic meaning of fields (like preLinePeriodQuantity) is consistently applied in your billing engine.


15839-15843: Updated Discounts in "InvoiceUsageBasedRateCard".
The discounts property now points to BillingDiscounts, ensuring schema consistency across rate card types. Confirm that the usage-based rate card logic reflects this structural update.


17960-17967: "Discounts" Reference in Rate Card for Flat Fee.
Here the discounts property now uses the unified Discounts schema with a note that only percentage discounts are supported for flat fee rate cards. Ensure that validation logic enforces this restriction.


18115-18121: "Discounts" Field Update in Rate Card Schema.
The schema now references Discounts for rate cards, maintaining the new abstraction. Verify that any business rules regarding which discount types are permitted on a given rate card are correctly enforced.


19368-19374: Integration of "Discounts" in Price Details.
The discounts field in the pricing section now references Discounts, and the property titles and descriptions are updated accordingly. Double-check that the provided empty example for Price (i.e. {}) is intentional.


19487-19494: "Discounts" Field in Plan Schema.
The plan schema now includes a discounts property referencing Discounts along with a locally unique identifier. Please verify that the pattern for the resource identifier remains valid in the context of the updated discount model.


19527-19533: Plan Schema: Inclusion of Discounts with Duration.
The addition of a discounts field within the plan’s duration details is consistent with the refactored model. Ensure that the documentation comprehensively explains how these discounts interact with the plan’s duration and pricing.


19609-19615: "Discounts" Reference Consistency in Plan Schema.
The final hunk updates the discounts property in the plan schema to reference Discounts and includes a title and description. Confirm that any related fields (such as activeFrom) are validated together with the new discount structure.

openmeter/productcatalog/http/mapping.go (6)

75-75: Improved discount handling in FlatFeeRateCard

The code now directly passes discounts through the new FromDiscounts function, simplifying the implementation by removing intermediate conversion steps. This change aligns with the PR's objective to update the discount structure into a unified format that supports both percentage and usage values.


107-107: Consistent discount handling across rate card types

The discount handling in UsageBasedRateCard now matches the approach used in FlatFeeRateCard, ensuring consistent behavior across different rate card types. This consistency is important for maintainability.


320-339: Well-structured function for discount conversion

The FromDiscounts function has been updated to return a pointer to api.Discounts instead of a slice and error. This change properly implements the new discount structure that permits a single discount per type (either percentage or usage).

The function correctly:

  1. Returns nil for empty discounts
  2. Properly maps both usage and percentage discount types
  3. Uses a more type-safe approach with dedicated fields

This simplifies error handling in the calling code while maintaining the necessary functionality.


459-465: Proper bidirectional discount conversion in FlatFeeRateCard

The discount conversion is now handled through the updated AsDiscounts function with appropriate error handling. This ensures that any conversion issues are properly reported and managed.


513-519: Consistent discount handling in AsUsageBasedRateCard

The discount handling in the AsUsageBasedRateCard function mirrors the approach used in AsFlatFeeRateCard, ensuring consistent implementation across different rate card types.


523-544: Comprehensive discount conversion logic

The AsDiscounts function effectively handles the conversion from API discount models to internal discount models with:

  1. Proper null handling (returns empty structure for nil input)
  2. Independent processing of usage and percentage discounts
  3. Appropriate error handling for conversion failures
  4. Clear structure that parallels the FromDiscounts implementation

This function completes the bidirectional conversion needed for the new discount format.

api/openapi.cloud.yaml (12)

12272-12300: Validate Discount Percentage and DiscountReason Schemas
The DiscountPercentage schema now explicitly requires a percentage between 0 and 100, which is appropriate. Similarly, DiscountReasonMaximumSpend and DiscountReasonRatecardPercentage correctly require a type property. Please verify that these naming conventions align with the overall refactoring strategy and that all related documentation is updated.


12375-12390: Review Discounts Aggregator Schema
The newly introduced Discounts schema aggregates percentage and usage discount objects. This approach simplifies discount handling by consolidating both types. Consider clarifying in the description how the full discount is computed if both properties are populated.


14653-14660: Confirm Updated Discounts Reference in InvoiceFlatFeeRateCard
The InvoiceFlatFeeRateCard now references BillingDiscounts for its discounts property. This update appears consistent with the new discount structure. Ensure that any related documentation in the client or backend systems is updated accordingly.


14692-14704: Review New InvoiceLineAmountDiscount Schema
The newly defined InvoiceLineAmountDiscount schema correctly mandates required fields such as createdAt, updatedAt, id, reason, and amount. The properties follow the expected format. No issues were found in this hunk.


14730-14736: Verify Reason Property Reference Update
Updating the reason property to reference BillingDiscountReason improves consistency across discount schemas. Please ensure that this change is reflected in any consuming services or documentation.


14742-14784: Assess InvoiceLineDiscounts and External IDs Update
The changes in this section add InvoiceLineAppExternalIds and redefine InvoiceLineDiscounts to include both amount and usage arrays. The multi-line descriptions (using |-) enhance readability. Overall, the changes look consistent with the new discount model.


15769-15776: Confirm Discounts Reference in InvoiceUsageBasedRateCard
The InvoiceUsageBasedRateCard now references BillingDiscounts for the discounts property. The description is clear, and the update aligns with the new rate card structure.


17785-17792: Verify Consistent Schema Naming for Rate Card Discounts
In this section, the discounts property references the unified Discounts schema (instead of BillingDiscounts as seen elsewhere). Please ensure that the naming difference between BillingDiscounts and Discounts is intentional and clearly documented. If they are meant to be the same, consider unifying the naming to avoid confusion.


17934-17941: Ensure Uniform Discount Schema References on Rate Cards
Similar to the previous hunk, the discounts property here references Discounts. Confirm that using Discounts (and not BillingDiscounts) in rate card definitions is deliberate and that downstream systems expect this schema.


19214-19221: Validate Discounts Integration in Price Schema
The pricing schema now includes a discounts property referencing Discounts. This integration appears consistent and clear.


19295-19302: Review Discounts in Plan Definition
The discounts property under the plan now references Discounts. The description “The discounts on the plan.” is clear but consider adding an example or further detail if needed in future iterations.


19377-19384: Confirm Discounts Usage in Resource Identifier Schema
The discounts property is again updated to reference Discounts. The definitions are consistent; however, verify that the use of the Discounts schema (across multiple components) is uniformly implemented across your API documentation and backend logic.

openmeter/productcatalog/discount_test.go (9)

17-27: Successfully implemented tests for the new Discounts structure with PercentageDiscount

The test case has been properly updated to use the new Discounts structure, correctly initializing the Percentage field with a pointer to a PercentageDiscount. This matches the structure definition shown in the relevant code snippets, ensuring compatibility with the updated API schema.


30-35: Test case properly handles UsageDiscount initialization

The test case correctly initializes the Usage field with a pointer to a UsageDiscount with the appropriate quantity value. The structure matches the updated code design shown in the relevant snippets.


40-49: JSON serialization/deserialization tests updated appropriately

The changes correctly update the JSON marshaling and unmarshaling operations to work with the new Discounts type. The test properly initializes an empty Discounts struct for unmarshaling and correctly asserts equality between the original and deserialized structures.


58-75: Equality test cases properly refactored for the new Discounts structure

The test cases for equality checks have been correctly updated to use the new Discounts structure with pointers to discount types. This refactoring maintains the original test's intent while adapting to the new API design.


78-90: Difference test case updated correctly

The test case correctly tests inequality between different discount types by comparing a Discounts with a Percentage field to one with a Usage field. This properly verifies that the equality comparison functions as expected between different discount configurations.


111-117: Validation test refactored appropriately

The validation test case now correctly initializes a Discounts struct with a Percentage field, ensuring compatibility with the new API structure. The test continues to validate that a 50% discount is considered valid.


120-126: Invalid percentage test case correctly updated

The test case properly validates that a percentage discount exceeding 100% is considered invalid, using the new Discounts structure. This ensures that the validation logic still works correctly with the refactored types.


127-135: Added test case for valid usage discount

A new test case has been added to verify that a usage discount with a positive quantity is considered valid. This enhances test coverage by ensuring that both discount types are properly validated.


136-144: Added test case for invalid usage discount

A new test case has been added to verify that a usage discount with a negative quantity is correctly identified as invalid. This enhances test coverage and ensures that the validation logic properly handles invalid usage discounts.

openmeter/billing/discount.go (12)

76-81: New Discounts struct properly implements the Clonable interface

The Discounts struct has been added with proper field types that match the structure in the product catalog. The compiler validation ensures that it correctly implements the models.Clonable interface, which is important for proper object copying.


83-95: Clone method properly implemented for deep copying

The Clone method correctly creates a new Discounts instance with deep copies of the Percentage and Usage fields, properly handling nil pointers. This ensures that mutations to the cloned object don't affect the original.


97-99: IsEmpty method implemented correctly

The IsEmpty method leverages the lo.IsEmpty function to check if the Discounts object is empty. This is a concise and effective implementation.


101-111: ValidateForPrice method handles validation delegation properly

The method correctly delegates validation to either the Percentage or Usage discount's ValidateForPrice method if present, providing proper validation for the combined structure. The method also correctly handles the case when neither discount type is present.


113-124: Updated discountReason interface with new method signatures

The interface now includes methods for checking the discount type and converting to specific discount types. This enhances type safety by providing explicit methods for type conversion.


128-142: Well-structured enum for discount reason types

The DiscountReasonType enum is defined with clear constant values and a Values method that returns all possible values. This is useful for validation and serialization purposes.


144-152: Added MaximumSpendDiscount type and updated DiscountReason struct

The MaximumSpendDiscount type has been added to represent maximum spend induced discounts. The DiscountReason struct has been updated with a new type field to discriminate between different discount reason types.


154-191: NewDiscountReasonFrom function updated to handle all discount types

The function has been updated to handle all discount types, including the new MaximumSpendDiscount type. The function correctly sets the appropriate type field and initializes the corresponding discount field.


193-229: MarshalJSON method updated for all discount reason types

The method now properly handles all discount reason types, including the new MaximumSpendDiscountReason. The serialization creates appropriate structures based on the discount type, ensuring correct JSON representation.


231-264: UnmarshalJSON method updated for all discount reason types

The method has been updated to correctly deserialize all discount reason types from JSON, setting the appropriate fields based on the type. The method includes proper error handling for invalid JSON.


266-300: Added type accessor and conversion methods for DiscountReason

New methods have been added to access the discount reason type and convert to specific discount types (AsRatecardPercentage, AsRatecardUsage, and AsMaximumSpend). These methods enhance type safety by providing explicit conversions with proper error handling.


302-313: Added Validate method for DiscountReason

The method correctly delegates validation to the appropriate discount type, with proper error handling for invalid discount types. This ensures that all discount reasons are properly validated.

api/spec/src/billing/invoices/discounts.tsp (8)

24-24: Updated InvoiceDiscountBase to use BillingDiscountReason

The reason field in the InvoiceDiscountBase model has been updated to use the new BillingDiscountReason type instead of the removed InvoiceDiscountReason enum. This aligns with the PR objective to restructure discounts.


43-57: Added InvoiceLineDiscounts model to organize discounts by type

A new model InvoiceLineDiscounts has been added to represent discounts applied to invoice lines, organized by type (amount or usage). This aligns with the PR objective to allow a single discount per type by providing clear separation between discount types.


64-82: Renamed and updated InvoiceLineUsageDiscount model

The model has been renamed from InvoiceLineDiscountUsage to InvoiceLineUsageDiscount for improved clarity and consistency. The model maintains all the necessary fields from InvoiceDiscountBase and adds usage-specific fields.


88-98: Renamed and updated InvoiceLineAmountDiscount model

The model has been renamed from InvoiceLineDiscountAmount to InvoiceLineAmountDiscount for improved clarity and consistency. This naming convention better describes the purpose of the model.


139-149: Added BillingDiscounts model to consolidate discount types

A new model BillingDiscounts has been added to consolidate percentage and usage discounts into a single structure. This aligns with the PR objective to modify the discount structure to permit only a single discount per type.


154-159: Added DiscountReasonType enum for discount categorization

A new enum DiscountReasonType has been added to categorize discount reasons, with values for maximum spend, ratecard percentage, and ratecard usage. This enhances type safety and clarity in discount reason representation.


164-170: Added BillingDiscountReason union with discriminated values

A new union BillingDiscountReason has been added with discriminated values based on the type field, allowing for clear differentiation between different discount reason types. This improves type safety and clarity.


175-196: Added specific models for different discount reason types

Three new models have been added for different discount reason types: DiscountReasonMaximumSpend, DiscountReasonRatecardPercentage, and DiscountReasonRatecardUsage. Each model includes the appropriate fields and type discriminator. This ensures proper typing for different discount reasons.

openmeter/billing/adapter/invoicelinediff.go (7)

60-62: Added IsEmpty method to diff struct

The IsEmpty method has been added to the diff struct to check if there are any items to delete, update, or create. This is a useful utility method that simplifies condition checks throughout the code.


64-72: Replaced discountWithLine with generic withLine struct

The discountWithLine struct has been replaced with a generic withLine[T any] struct and appropriate type aliases. This improves code reuse and type safety for different types of discounts.


80-81: Updated invoiceLineDiff struct for separate discount types

The invoiceLineDiff struct has been updated to replace the Discounts field with separate UsageDiscounts and AmountDiscounts fields using the new generic types. This aligns with the PR objective to separate different discount types.


351-375: Updated handleLineDependantEntities for separate discount handling

The function has been updated to handle usage and amount discounts separately, first checking the database state of discounts and then processing each discount type individually. This aligns with the PR objective to modify the discount structure.


378-386: Added diffable interface and handleLineDiscountsResult struct

A new diffable[T any] interface has been added to define the requirements for types that can be diffed, along with a handleLineDiscountsResult[T] struct to hold the results of diffing. This enhances code clarity and type safety.


388-421: Refactored handleLineDiscounts to be generic

The handleLineDiscounts function has been refactored to be generic, allowing it to work with any type that implements the diffable[T] interface. This improves code reuse and type safety.


423-476: Refactored handleLineDiscountUpdate to be generic

The handleLineDiscountUpdate function has been refactored to be generic, with proper error handling and type conversions. The function correctly identifies discounts that need to be created, updated, or deleted.

openmeter/ent/schema/billing.go (5)

22-23: Consider verifying JSON scanning logic
Implementation looks good, but please ensure these new JSON scanners handle all edge cases (e.g., null values, empty objects, large discount sets) to avoid downstream parsing errors.


429-431: Confirm references to new discount edges
The newly introduced edges separating usage-based and amount-based discounts seem aligned with the refactor goals. Please verify that all references in queries, resolvers, and tests have been updated to reflect these new edge names.


513-515: Introducing a base discount struct is a solid step
This shared base struct cleanly factors out fields common to multiple discount types.


517-541: Check enumerations and JSON fields for consistency
Please confirm that the 'reason' enum usage and the 'source_discount' JSON field remain consistent across their consumers.


627-685: Usage discount struct appears consistent
No apparent issues with this usage-based discount structure; it aligns well with the design.

openmeter/ent/db/paginate.go (4)

494-539: Pagination for flat-fee line config
Implementation follows the established pattern and looks correct.


542-587: Pagination for invoice lines
This method is consistent with other paginated query patterns.


590-635: Pagination for line discounts
Logic mirrors existing pagination structure and appears correct.


638-683: Pagination for usage-based line discounts
This function consistently applies the pagination approach used throughout the codebase.

openmeter/ent/db/billinginvoiceline/billinginvoiceline.go (6)

94-97: New edge labels for usage and amount discounts
Separating usage- vs. amount-based discount edges helps clarify discount types and references.


135-148: Distinct tables and columns for discount types
Defining separate inverse tables and columns for usage vs. amount discounts supports the broader discount refactor.


484-496: Ordering by line usage discounts
The neighbor-based ordering logic here aligns well with ENT’s approach.


498-510: Ordering by line amount discounts
Implementation parallels the usage discounts approach, ensuring consistency.


567-573: Usage discount step function
No issues; the O2M edge logic looks standard and correct.


575-580: Amount discount step function
Implementation is consistent with the usage discount step, preserving clarity in the discount architecture.

openmeter/productcatalog/discount.go (16)

8-8: Import is correctly added for lo package.

The lo package is imported to use its helper functions for collection operations, which is needed for the Clone and IsEmpty methods later in the code.


26-32: Method signature change on PercentageDiscount.Hash aligns with refactoring.

The method signature has been changed from a pointer receiver to a value receiver. This approach is consistent with the immutable nature of the struct and ensures safer handling in concurrent environments.


34-42: Validation logic properly retained in PercentageDiscount.Validate.

The validation logic ensures percentage values remain between 0 and 100, maintaining business logic integrity while simplifying the overall discount structure.


44-46: Simplified ValidateForPrice method correctly forwards to Validate.

This change simplifies the code by delegating to the standard Validate method, which is appropriate since percentage discounts have the same validation rules regardless of price type.


48-52: PercentageDiscount.Clone method correctly implements deep copying.

The method properly creates a new instance with the same value, maintaining the immutability pattern expected in the codebase.


64-70: UsageDiscount.Hash implementation follows the pattern established for PercentageDiscount.

The method signature has been changed to use a value receiver, consistent with the changes to PercentageDiscount.


72-80: UsageDiscount.Validate correctly enforces positive quantity requirement.

The validation ensures that usage discounts cannot have negative values, which is a crucial business rule.


82-99: UsageDiscount.ValidateForPrice logic improved.

The method now calls Validate() first, following the DRY principle, and then performs price-specific validations. The check for flat price compatibility is appropriately maintained.


101-105: UsageDiscount.Clone correctly implements deep copying.

The method creates a new instance with the same values, consistent with the cloning pattern elsewhere in the codebase.


110-110: Added Validator interface implementation for Discounts.

The code correctly adds the Validator interface implementation for the Discounts type, which is necessary for the new validation method added below.


113-116: Core redesign: Discounts refactored to allow single discount per type.

The Discounts type has been completely redesigned from an array of multiple discounts to a struct with exactly one optional discount of each type. This aligns with the PR objective to allow only a single discount per type.


118-128: Equal method updated to work with the new Discounts structure.

The method now correctly compares the two optional discount pointers using the equal.HasherPtrEqual helper, which safely handles nil pointers and proper equality comparison.


130-142: Clone method properly handles the new Discounts structure.

The method correctly creates a deep copy of the Discounts struct, using lo.ToPtr to convert the cloned values to pointers. This ensures proper immutability and prevents unintended side effects when modifying cloned objects.


144-164: New Validate method added for Discounts.

The method properly handles nil receiver checks and validates both discount types if they exist. The error messages are appropriately prefixed with the discount type for clarity in error reporting.


166-186: ValidateForPrice correctly checks both discount types against the price.

The method now uses the new IsEmpty() helper to check if any discounts exist before requiring a price. It then validates each discount type against the price if they exist, providing clear error messages.


188-190: IsEmpty helper method added to check if Discounts is empty.

The method delegates to lo.IsEmpty(), which properly checks if all fields in the struct are zero values, including nil pointers. This provides a clean way to check if no discounts are defined.

openmeter/ent/db/client.go (13)

31-31: Import added for the new BillingInvoiceLineUsageDiscount module

This import is correctly added to support the new discount structure that separates unit and amount discounts into different tables, as outlined in the PR objectives.


93-94: Addition of BillingInvoiceLineUsageDiscount client to the Client struct

This field properly adds the client for the new BillingInvoiceLineUsageDiscount entity, which is a key part of the refactoring to allow only a single discount per type.


171-171: Initialization of BillingInvoiceLineUsageDiscount client in the init method

The initialization is correctly implemented, ensuring the new client is properly set up when a new Client instance is created.


303-303: Adding BillingInvoiceLineUsageDiscount to the Tx method

The BillingInvoiceLineUsageDiscount client is correctly added to the transaction configuration, ensuring consistent transaction management.


362-362: Adding BillingInvoiceLineUsageDiscount to the BeginTx method

Similar to the Tx method, this ensures proper transaction management for the new discount entity.


421-423: Including BillingInvoiceLineUsageDiscount in the Use method

This properly adds hook support for the new client, ensuring that mutation hooks can be applied to the BillingInvoiceLineUsageDiscount entities.


443-445: Including BillingInvoiceLineUsageDiscount in the Intercept method

This correctly adds interceptor support for the new client, ensuring that query interceptors can be applied to queries for BillingInvoiceLineUsageDiscount entities.


487-488: Adding mutation support for BillingInvoiceLineUsageDiscount

This properly adds support for handling mutations (creations, updates, deletions) of BillingInvoiceLineUsageDiscount entities to the Mutate method.


2661-2675: Added QueryLineUsageDiscounts method to BillingInvoiceLineClient

This new method correctly implements the ability to query usage discounts associated with a billing invoice line, using the appropriate edge and table configuration.

The implementation follows the same pattern as other query methods and correctly sets up the SQL graph path for the relationship.


2677-2678: Modified QueryLineAmountDiscounts to use LineAmountDiscountsTable

This change updates the edge name used in the QueryLineAmountDiscounts method to reflect the new separation of discounts into different tables. The method now correctly uses the "line_amount_discounts" edge for amount discounts.

Also applies to: 2685-2685


7472-7493: Updated hooks and interceptors structures to include BillingInvoiceLineUsageDiscount

These changes correctly update the internal structures used to track hooks and interceptors for each client type, ensuring that the new BillingInvoiceLineUsageDiscount client is properly included.


2915-3062: Implementation of BillingInvoiceLineUsageDiscountClient methods

The implementation of the BillingInvoiceLineUsageDiscountClient is thorough and complete, providing all necessary methods for creating, reading, updating, and deleting BillingInvoiceLineUsageDiscount entities. The client follows the same pattern as other clients in the codebase, ensuring consistency.

Key methods include:

  • Create/CreateBulk/MapCreateBulk for entity creation
  • Update/UpdateOne/UpdateOneID for entity updates
  • Delete/DeleteOne/DeleteOneID for entity deletion
  • Query/Get/GetX for entity retrieval
  • QueryBillingInvoiceLine for navigating relationships
  • Hooks/Interceptors for extension points
  • mutate for handling mutations

This comprehensive implementation ensures that the new discount structure can be fully managed through the client API.


1-7496:

Details

❓ Verification inconclusive

Verify the discount structure transition in the database

The code changes appropriately implement the separation of unit and amount discounts into different tables, as mentioned in the PR objectives. However, it would be valuable to ensure that there's a migration plan to handle existing data.

Consider verifying that:

  1. There's a database migration script to create the new table structure
  2. There's a data migration strategy to move existing discounts to the appropriate new tables
  3. Application code that previously used the combined discount structure is updated to use the separated structure

🏁 Script executed:

#!/bin/bash
# Let's examine the database migration scripts to verify proper handling of discount tables

# First, check for migration files related to discounts
fd migration --exec grep -l "discount|LineDiscount" {}

Length of output: 107


I'll run a new script that restricts the search to files only, to see if any migration scripts mention discount adjustments:


🏁 Script executed:

#!/bin/bash
# Re-run the migration script search command focusing on files only.
fd -t f migration | xargs grep -Hin "discount\|LineDiscount"

Length of output: 62


Action Required: Confirm Discount Migration Strategy

The latest verification using automated file searches did not locate any migration scripts referencing “discount” or “LineDiscount.” While the code changes in the client file clearly separate unit and amount discounts, it’s unclear if a corresponding migration has been implemented.

Please verify that:

  • A migration script exists to create the new table structure for the separated discount types.
  • A data migration strategy is in place to move any existing discount information into the appropriate new tables.
  • All parts of the code that previously depended on a combined discount structure have been updated to work with the new separated structure.

If these migration changes are handled outside of what was searched, kindly confirm manually that the migration plan covers these aspects.

openmeter/ent/db/setorclear.go (5)

1136-1141: Consistent nil-check pattern for invoicing external ID.
These lines follow the established SetOrClear pattern correctly, returning ClearInvoicingAppExternalID() when the input is nil.


1143-1148: Verified one-entity variant.
Same pattern as the multi-entity version above. Implementation looks consistent and maintains clarity.


1164-1176: Selective discount reason field management.
The logic for setting or clearing SourceDiscount fits well, closely mirroring other SetOrClear methods. Ensure that upstream code calling these functions properly handles the nil case if needed.


1178-1190: New method to set or clear discount type.
Looks correct and consistent with other SetOrClear implementations, returning the cleared state when value == nil. Carefully verify that any existing references to discount type are updated to reflect this new workflow.


1220-1303: Addition of SetOrClear methods for usage-based line discounts.
All newly introduced usage-discount methods (e.g., SetOrClearDeletedAt, SetOrClearChildUniqueReferenceID, etc.) maintain the same nil-check pattern used elsewhere. This uniform approach is good for consistency. No apparent logical errors.

openmeter/billing/invoicelinediscount.go (20)

23-26: Expanded discount base fields.
Adding or exposing ChildUniqueReferenceID, ExternalIDs, and Reason into LineDiscountBase extends the discount details. Implementation is straightforward.


32-33: Validation of Reason.
The additional validation call ensures discount reasons aren’t silently ignored. This is a good practice to catch improper discount usage early.


47-49: Universal accessor for ChildUniqueReferenceID.
Introducing this getter aligns with the new discount reuse mechanism. Code is concise and correct.


52-53: Integration with ManagedModelWithID.
Embedding ManagedModelWithID into LineDiscountBaseManaged centralizes metadata (like creation timestamps). This looks consistent with the rest of the codebase.


105-107: Managed version of amount discount.
The embedded AmountLineDiscount plus ManagedModelWithID provides a clean approach for storing discount details with an ID. Implementation is consistent with established patterns.


120-122: Equality check for managed discount.
Checking ManagedModelWithID equality is important for ensuring the correct match of persistent IDs. Implementation is correct.


133-135: Cloning logic for managed discount.
The approach of shallow-cloning the ManagedModelWithID and deeper cloning of the embedded discount ensures safe duplication. Good job.


138-140: ContentsEqual helper method.
Separating content equality from full equality (which includes ID/t timestamps) is a useful pattern. Implementation logically fits.


143-151: Helper for reassigning managed fields.
WithManagedFieldsWithID reuses existing discount content with new ID fields. This is beneficial for partial object updates without losing discount data.


153-203: Collection of AmountLineDiscountManaged.
Methods like Clone, SumAmount, GetByID, etc., add essential bulk operations on discounts. The usage of lo.Map for immutability is consistent with best practices.


255-257: Usage-based discount with ManagedModelWithID.
Mirrors the structure of the amount-based discount. Implementation remains consistent.


288-290: Usage-based discount content equality.
Again, splitting content equality from ID equality helps maintain or reuse objects more flexibly.


292-301: Methods for retrieving and updating managed fields in usage-based discount.
Follows the standard pattern used by the other discount types. Straightforward approach.


303-310: Introduction of UsageLineDiscountsManaged slice type.
Creating a dedicated slice type for usage-line discounts helps unify logic for validations and ID reassignments.


312-333: LineDiscounts struct to group amount & usage discounts.
This central struct is an effective consolidation of discount data. The usage of separate fields for Amount vs. Usage is clear.


335-351: Validate method for LineDiscounts.
Iterating over Amount and Usage discounts ensures no discount is overlooked. Good error accumulation pattern.


353-369: ReuseIDsFrom method to reassign persistent IDs.
By matching ChildUniqueReferenceID, existing discounts can keep IDs, preventing duplication. This addresses typical invoice-line discount reusability scenarios.


370-372: IsEmpty check.
Simple function to confirm if no discounts exist – minimal but handy. Implementation is correct.


374-378: entityWithReusableIDs interface.
A flexible approach that generalizes ID-reuse for different discount entities.


380-425: ReuseIDsFrom generic function.
Applies a neat approach for bridging new discount data with existing records. Code is thorough, checks for ChildUniqueReferenceID != nil, and merges IDs.

openmeter/ent/db/billinginvoicelinediscount/where.go (6)

105-108: Initial helper for InvoicingAppExternalID.
This depicts the basic equality check. Implementation is aligned with existing naming and usage patterns in the ent-based predicates.


120-123: Base predicate for Type.
Introduces a direct equality check on the type field, consistent with Ent’s approach to generating predicate methods.


545-573: Reason* predicates for discount reason type.
These new methods (EQ, NEQ, In, NotIn) expand the filtering capabilities on discount reasons. They closely match patterns from other fields.


575-648: Expanded InvoicingAppExternalID predicate set.
Supports advanced queries (e.g., GT, LT, Contains, HasPrefix) for external ID. This thoroughly covers typical use cases for partial matching.


740-749: SourceDiscount nil checks.
The ability to check whether source_discount is set or not can be vital for queries that filter out lines lacking an underlying discount reason. No issues found.


750-823: Comprehensive set of Type queries.
Complete coverage for comparisons, null checks, prefix/suffix checks, and case-insensitive matching. This is consistent with other string fields in ent.

openmeter/ent/db/billinginvoicelineusagediscount/where.go (2)

1-14: Code generation acknowledged.

This file appears to be auto-generated by Ent (as indicated by the header comment). Typically, no manual modifications are required. All predicates and struct definitions align with Ent’s default patterns for building query filters.


758-771: Logical composition functions (And, Or, Not) are standard.

These methods are standard Ent code for combining predicates. They look correct and consistent with typical Ent usage, generating clean SQL expressions without duplication.

e2e/productcatalog_test.go (1)

188-206: Verify discount initialization logic.

The introduction of DiscountPercentage with models.NewPercentage(10) and assigning it to Discounts.Percentage is aligned with the single-discount-per-type approach. This straightforward pattern cleanly sets a 10% discount.

test/billing/adapter_test.go (4)

647-682: Comprehensive discount setup on child lines.

Here, multiple amount-based discounts are constructed for the detailed child line. This reflects the new single-discount-per-type approach, though the test covers multiple discrete amounts. The logic is clear, attaching each discount with a unique description or reference ID.


694-713: Cleaning managed fields before mutation.

Removing ManagedModelWithID fields for test comparisons is a good approach to ensure that auto-generated or database-managed fields do not interfere with test validation.


720-769: Reusing existing discount ID and adjusting discount amounts.

Searching for and retaining the ID of the manual discount prevents the creation of duplicate database entities. This ensures stable references and correct discount evolution rather than insertion of new discounts.


788-841: Validating persisted discount updates.

The step-by-step validation of updated discounts (e.g., verifying updated descriptions, ensuring partial updates persist IDs) confirms correct reuse of existing discount records. This is a thorough approach favorable for regression coverage.

openmeter/ent/db/billinginvoiceline_create.go (5)

21-21: New import for usage-based discounts.
This import line references the newly introduced billinginvoicelineusagediscount package. It appears consistent with the changes enabling usage-based discounts.


417-421: Method added for linking usage-discount IDs.
This method, AddLineUsageDiscountIDs, correctly follows Ent’s pattern for adding a one-to-many edge based on usage-discount IDs. No issues noted.


423-430: Method added for linking usage-discount entities.
AddLineUsageDiscounts properly collects discount entity IDs and defers to AddLineUsageDiscountIDs. Implementation seems straightforward.


432-436: Method added for linking amount-discount IDs.
AddLineAmountDiscountIDs mirrors its usage-discount counterpart and cleanly adds the related edges. Looks good.


438-445: Method added for linking amount-discount entities.
AddLineAmountDiscounts properly iterates over the discount objects to gather IDs and delegate to AddLineAmountDiscountIDs. Implementation is consistent.

api/client/javascript/src/client/schemas.ts (14)

2330-2332: Enhanced documentation for correlation ID is valuable

The updated documentation clarifies the importance of maintaining the same correlation ID during invoice edits, particularly in progressive billing scenarios. This helps prevent incorrect discount calculations.


2337-2341: Good addition of structured discount reason type

Adding the BillingDiscountReason union type provides a clear structure for different discount reason types, making the API more consistent and easier to understand.


2363-2369: Well-structured BillingDiscounts type supports the single discount per type goal

The new BillingDiscounts type elegantly consolidates both percentage and usage discounts into a single structure with optional fields for each, directly implementing the PR's goal of allowing a single discount per type.


3399-3405: Improved DiscountPercentage type with better documentation

The enhanced DiscountPercentage type with better documentation improves clarity for API consumers.


3406-3463: Comprehensive discount reason types with appropriate metadata

The addition of structured discount reason types (DiscountReasonMaximumSpend, DiscountReasonRatecardPercentage, and DiscountReasonRatecardUsage) with discriminator properties and correlation IDs provides a robust framework for tracking the origin and purpose of discounts throughout the system.


3478-3484: Consistent Discounts type aligns with overall architecture

The Discounts type follows the same pattern as BillingDiscounts, maintaining consistency in the codebase while supporting the single discount per type approach.


4978-4978: Updated discounts property type for invoice lines

The change to use InvoiceLineDiscounts type reflects the new structure for representing discounts on invoice lines, supporting the separation of amount and usage discounts.


5197-5197: Updated discounts type for consistency

Changing to BillingDiscounts type ensures consistency across the API for discount representations.


5218-5219: Improved naming of InvoiceLineAmountDiscount

Renaming from InvoiceLineDiscountAmount to InvoiceLineAmountDiscount improves clarity and consistency with the naming pattern of other discount types.


5247-5247: Updated reason property type

Changed to use the new BillingDiscountReason union type for better type safety and clarity.


5258-5275: Well-designed InvoiceLineDiscounts structure

The InvoiceLineDiscounts type effectively organizes discounts by category (amount vs. usage), with clear documentation explaining how each type affects the invoice line calculation. This supports the PR objective while maintaining the array representation for calculated discounts.


5320-5368: Comprehensive InvoiceLineUsageDiscount type

The new InvoiceLineUsageDiscount type provides a complete structure for representing usage-based discounts on invoice lines, including all necessary metadata and progressive billing support via the preLinePeriodQuantity field.


5742-5742: Consistent updates to discount property types

All discount property types have been updated consistently throughout the schema to use the new structured discount types, ensuring a cohesive implementation of the single discount per type approach.

Also applies to: 5935-5935, 7448-7448, 7567-7567, 8587-8587, 8646-8646, 8704-8704


9264-9267: Complete exports for all new types

All newly introduced types are properly exported, making them available for use by API consumers. This ensures the changes are fully accessible throughout the codebase.

Also applies to: 9379-9386, 9479-9483, 9493-9494

openmeter/ent/db/billinginvoicelineusagediscount_query.go (3)

20-32: Well-structured query builder
The struct aligns with ent's standard patterns for query builders, providing targeted methods for filtering and ordering.


65-85: Verify edge definitions
“QueryBillingInvoiceLine” relies on the M2O edge linking BillingInvoiceLineUsageDiscount to BillingInvoiceLine. Confirm that the schema definition for this relationship is correct and enforced at the database level.


187-295: Test coverage for multiple fetch methods
Methods like All, IDs, Exist, and Clone handle various query scenarios. Ensure comprehensive tests exist for edge cases such as no matches and unusually large result sets to guarantee reliability.

openmeter/ent/db/billinginvoiceline_query.go (4)

20-20: Import for usage discount
The added import for billinginvoicelineusagediscount is consistent with the newly integrated usage discount features.


31-46: New fields for usage & amount discounts
Fields like withLineUsageDiscounts and withLineAmountDiscounts expand the query builder to handle discount retrieval. Confirm that any required migrations or schema changes are fully synchronized.


193-235: Dedicated queries for usage & amount discounts
The methods QueryLineUsageDiscounts and QueryLineAmountDiscounts are clear entry points for retrieving their respective discounts. Double-check that the edges line_usage_discounts and line_amount_discounts are declared correctly in the schema.


490-509: Clone method updated
Adding the new discount-related fields in Clone ensures that all query parameters are fully copied. This looks good for maintaining consistent query behavior.

openmeter/ent/db/billinginvoiceline.go (4)

117-120: Introducing separate discount edges
LineUsageDiscounts and LineAmountDiscounts clarify the distinction between usage-based and amount-based discounts. This naming reduces confusion and aligns with the single discount per type requirement.


129-130: Expanding loadedTypes
Increasing the loadedTypes array from 9 to 10 accounts for the new discount edges. Verify array indexing to ensure no off-by-one errors.


185-201: New edge retrieval methods
LineUsageDiscountsOrErr and LineAmountDiscountsOrErr enhance clarity and error handling if edges were not preloaded. This pattern promotes safer downstream usage.


536-544: Query methods for discount edges
QueryLineUsageDiscounts and QueryLineAmountDiscounts give consumers straightforward ways to fetch usage or amount discounts. The separation matches the redesigned discount model.

openmeter/ent/db/billinginvoicelineusagediscount_delete.go (8)

1-14: No issues with the generated boilerplate.
This section contains standard Ent-generated headers and package imports.


15-20: Struct naming and layout are clear.
BillingInvoiceLineUsageDiscountDelete correctly encapsulates the mutation and hooks related to deleting these entities.


22-26: Flexible predicate design.
The Where method allows chaining of predicates for selective deletion. This is consistent with Ent patterns.


28-31: Deletion execution logic.
Exec looks standard: it delegates to hook processing before actual SQL execution.


42-57: Constraint error handling.
sqlgraph.DeleteNodes returns a constraint error if the deletion violates references. Wrapping it in ConstraintError is standard for Ent, and there's no apparent issue.


59-62: Single-entity delete builder.
BillingInvoiceLineUsageDiscountDeleteOne is a standard Ent pattern for operating on a single node.


64-68: Consistent method naming.
The Where method parallels the multiple-entity builder usage—keeps code structure uniform.


70-82: NotFoundError usage.
Returning a NotFoundError if zero rows are deleted is good practice for single-entity delete requests.

openmeter/ent/db/billinginvoiceline_update.go (8)

20-20: New import for usage discounts.
Line 20 adds "github.com/openmeterio/openmeter/openmeter/ent/db/billinginvoicelineusagediscount". This aligns with the single-discount-per-type refactor.


557-570: Usage discount edge additions.
AddLineUsageDiscountIDs and AddLineUsageDiscounts provide clarity for attaching usage discounts to a line.


572-585: Amount discount edge additions.
Similarly, AddLineAmountDiscountIDs and AddLineAmountDiscounts handle amount-based discounts. This separation matches the PR’s single-discount-per-type approach.


652-671: Removing usage discounts.
ClearLineUsageDiscounts, RemoveLineUsageDiscountIDs, and RemoveLineUsageDiscounts ensure that usage discounts can be fully or selectively detached from the invoice line.


673-692: Removing amount discounts.
ClearLineAmountDiscounts, RemoveLineAmountDiscountIDs, and RemoveLineAmountDiscounts provide counterpart functionalities for amount-based discounts.


1044-1088: O2M edge clearing for usage discounts.
When LineUsageDiscountsCleared is set, the code properly constructs the O2M edge specification for billinginvoicelineusagediscount.


1090-1133: Optional usage discount removals.
The logic with _spec.Edges.Clear and _spec.Edges.Add is a standard Ent approach for removing or adding references. No obvious concurrency or data race issues.


2318-2362: Amount discount edge updates.
Equivalent logic for line amount discounts, matching the usage discount logic. The pairing ensures uniform handling of each discount type.

openmeter/ent/db/billinginvoicelineusagediscount/billinginvoicelineusagediscount.go (8)

1-14: Generated file header.
Contains canonical Ent definitions; no issues spotted.


15-55: Enum definitions and table/field constants.
Correspond to the billing_invoice_line_usage_discounts schema. All references align with the PR’s discount separation.


57-82: Column array and validity checks.
Columns and ValidColumn are standard Ent patterns for ensuring queries target valid fields.


84-99: Default & value scanner structures.
NamespaceValidator, DefaultCreatedAt, DefaultUpdatedAt, and ValueScanner for reason_details are typical for initialization and custom marshalling.


101-109: Enum validation for Reason.
It enforces consistent discount reason types. This is in line with the single discount type usage.


111-133: OrderOption definitions.
Providing multiple ordering functions for precise query sorting is standard. No performance or readability issues found.


139-177: ByField ordering expansions.
ByLineID, ByChildUniqueReferenceID, etc., match the newly introduced fields. This is consistent.


179-191: Neighbor-based ordering via ByBillingInvoiceLineField.
Focuses on the M2O relationship with billing_invoice_lines. Implementation follows Ent’s neighbor-based ordering approach.

openmeter/ent/db/billinginvoicelineusagediscount_create.go (73)

1-14: Boilerplate generation.
Standard code comments and package references. No concerns.


21-27: Struct definition.
BillingInvoiceLineUsageDiscountCreate organizes mutation hooks, conflict strategy, and the config for creating usage discounts.


29-33: SetNamespace method.
namespace is required for the discount entity, consistent with the rest of the codebase.


35-47: CreatedAt field methods.
Allows explicit setting or nillable assignment. No performance or correctness issues.


49-61: UpdatedAt field methods.
Same pattern as CreatedAt, ensuring consistency in date fields.


63-75: DeletedAt field methods.
Supports soft-deletion or archival logic. Good for partial invoice record retention.


77-81: SetLineID.
Essential for linking to the BillingInvoiceLine. This matches the new discount architecture.


83-95: ChildUniqueReferenceID.
Helps track usage discount children. Graceful handling of nil for optional references.


97-109: Description field logic.
Optional field for discount clarifications or user notes.


111-115: SetReason method.
Valid discount reason ensures alignment with allowed discount types.


117-129: InvoicingAppExternalID.
Permits external system references; properly nillable.


131-135: SetQuantity.
Crucial for usage-based discount tracking. No issues.


137-149: PreLinePeriodQuantity.
Supports usage calculations for partial/look-back discount logic.


151-155: ReasonDetails.
Extracts additional structured discount data. The approach is consistent with ent's JSON scanning.


157-169: ID field setting.
Permits manual ID overrides, else defaults. Good for advanced use cases.


171-180: BillingInvoiceLine edges.
SetBillingInvoiceLineID and SetBillingInvoiceLine connect usage discounts to their parent line.


182-185: Mutation retrieval.
The Mutation() method is standard for advanced or custom logic.


187-191: Save method hooking.
Delegates to withHooks for any pre- or post-create steps. Ent best practice.


202-213: Exec/ExecX usage.
Same pattern as Save/SaveX, all standard Ent convenience methods.


215-229: defaults method.
Ensures timestamp and ID fields have default values if not set. Aligned with the new discount entity approach.


231-270: check method validations.
Throws ValidationError for missing required fields and edges. Enforces business logic: usage discount must have a reason, quantity, and linked invoice line.


272-296: sqlSave method.
Conducts the final DB insert; wraps constraint errors. Looks correct and consistent with Ent’s pattern.


298-374: createSpec logic.
Binds each user-specified field, adds edge for billing_invoice_line, and marshals the JSON reason_details.


376-397: OnConflict and upsert strategy.
Allows advanced conflict resolution. Well-aligned with the introduction of single discount entries.


399-410: OnConflictColumns convenience.
Lets callers specify columns to match on for upserts. No issues.


412-417: BillingInvoiceLineUsageDiscountUpsertOne struct.
Helper for "upsert" usage with a single discount.


419-423: BillingInvoiceLineUsageDiscountUpsert struct.
Wraps an UpdateSet for partial overrides on conflict.


425-453: Field update methods in upsert.
SetUpdatedAt(), UpdateUpdatedAt(), ClearDeletedAt(), etc. reflect typical upsert behavior.


455-465: LineID upsert logic.
Ensures the discount properly associates or re-associates to an invoice line upon conflict.


467-483: ChildUniqueReferenceID overrides.
Optional clearing or setting is consistent with the discount structure.


485-501: Description upsert.
Allows the discount description to be replaced or removed. No issues.


503-513: Reason upsert logic.
Stays consistent with the single discount reason approach.


515-531: InvoicingAppExternalID upsert.
Same pattern for updating or clearing external references.


533-543: Quantity upsert.
Allows re-specifying usage quantity on conflict.


545-561: PreLinePeriodQuantity upsert.
Can re-initialize usage discount’s pre-line figure if the row is re-inserted.


563-579: ReasonDetails upsert.
Lets advanced discount structure be updated or cleared.


581-606: Reuse create logic for "UpdateNewValues".
UpdateNewValues merges newly set fields, skipping ID/namespace/CreatedAt if already set.


608-617: Ignore & DoNothing for conflicts.
Ent’s built-in ways to handle uniqueness constraints.


619-624: DoNothing config.
Applies only to SQLite/PostgreSQL, consistent with typical Ent disclaimers.


626-633: Update logic in UpsertOne.
Allows the user to set custom conflict resolutions for each field, bridging auto-resolved merges with user overrides.


635-647: Helper methods for upsert updates.
Inline convenience calls for setting or clearing fields.


649-668: Similar approach for DeletedAt.
All upsert variations remain consistent.


670-682: line_id upsert methods.
Again, paralleling the logic from simpler fields.


684-703: child_unique_reference_id upsert methods.
Same pattern, no concerns.


705-724: description upsert methods.
No concurrency or logic issues.


726-738: reason upsert methods.
Inserting or updating the discount reason is consistent with single discount usage.


740-759: invoicing_app_external_id upsert methods.
Same approach for external references.


761-773: quantity upsert methods.
Re-applies usage discount quantity.


775-787: pre_line_period_quantity upsert methods.
Re-applies or clears pre-line usage quantity.


789-815: reason_details upsert methods.
JSON-based discount detail management.


817-830: Exec and ID retrieval in upsert.
ID() returns the newly inserted or updated discount ID, except in MySQL which lacks RETURNING.


832-853: IDX convenience method.
Wraps ID() with a panic on error pattern. Fine for test usage.


855-861: Bulk creation struct.
BillingInvoiceLineUsageDiscountCreateBulk allows multiple usage discounts insertion.


863-920: Bulk Save logic.
Orchestrates a batched insert, each builder running defaults and passing a createSpec. No concurrency issues evident.


931-942: Bulk Exec methods.
Same approach, returning or panicking on error.


944-964: Bulk OnConflict.
Applying conflict logic for multiple entities at once. Good design for batched usage.


966-976: OnConflictColumns for bulk.
Similar to single upsert approach, but extended for multiple rows.


979-983: BillingInvoiceLineUsageDiscountUpsertBulk struct.
Wrapper for advanced conflict resolution across multiple usage discount rows.


985-1012: UpdateNewValues for multiple discount create.
Resolves with new values across all batched discount creations.


1014-1023: Ignore logic in bulk upsert.
Same pattern as single-entity upsert.


1025-1030: DoNothing in bulk.
Ensures no conflict resolution for batch inserts in PostgreSQL/SQLite.


1032-1039: Update override for bulk upsert.
Lets the developer set custom resolution logic on each field for all rows.


1041-1053: Helper methods for updated_at.
Same approach repeated for each field in the discount struct.


1055-1074: deleted_at updates for bulk.
No concerns; pattern remains the same.


1076-1088: line_id upsert in bulk.
Assign or re-assign usage discount lines in multi-row context.


1090-1109: child_unique_reference_id in bulk.
Optional references are consistently managed.


1111-1130: description in bulk upsert.
Exact parity with single-row logic.


1132-1144: reason for each discount in batch.
No issues.


1146-1165: invoicing_app_external_id in batch.
Clear or override if needed.


1167-1179: quantity in bulk.
Same approach.


1181-1200: pre_line_period_quantity in batch.
Mirrors single discount handling.


1202-1221: reason_details in batch.
Upsert behavior repeated for discount details.


1223-1237: Exec logic in UpsertBulk.
Ensures that the user sets the conflict logic on the bulk builder, not on each single sub-builder.

openmeter/ent/db/billinginvoicelineusagediscount_update.go (4)

21-214: Well-structured update builder for multi-entity updates.

All setter, nillable setter, and clearer methods neatly follow Ent's design patterns and maintain good readability. The reliance on an internal mutation for state management is clear and consistent. No immediate issues or code smells found in these sections.


372-602: Single-entity update builder duplicates multi-entity logic effectively.

This one-entity update builder mirrors the multi-entity version in a conventional manner, providing straightforward usage for updating a single record. No novel issues detected, as the code reuses the same mutation patterns and validations.


603-750: Validation checks and default field handling are appropriate.

Automatically setting updated_at with UpdateDefaultUpdatedAt() ensures the timestamp is always fresh. The validator calls are consistent with the logic used for multi-entity updates. Everything is properly wrapped in Ent’s standard sqlSave flow.


1-750:

Details

❓ Verification inconclusive

Optional verification of test coverage.

These new methods appear correct, but to ensure comprehensive coverage, you could verify that relevant integration or unit tests exist for all field-updating paths (e.g., clearing fields, nillable setters, validation, and edge clearing).


🏁 Script executed:

#!/bin/bash
# Description: Search for test references to the newly introduced Update methods.

# Look for tests that call these new builder methods.
rg -A 10 "BillingInvoiceLineUsageDiscountUpdate\|BillingInvoiceLineUsageDiscountUpdateOne" --glob '*_test.go'

Length of output: 111


Action: Verify Test Coverage for BillingInvoiceLineUsageDiscount Update Methods

The updated builder methods look correct overall; however, the automated search for tests referencing BillingInvoiceLineUsageDiscountUpdate and BillingInvoiceLineUsageDiscountUpdateOne did not yield any results. Please manually verify that integration or unit tests are in place that cover:

  • Nillable setters (e.g., SetNillableDeletedAt, SetNillableLineID, etc.)
  • Field clearing functions (e.g., ClearDeletedAt, ClearDescription, ClearBillingInvoiceLine)
  • Validation logic in both update builders

If tests for these paths are missing or incomplete, consider adding them to ensure comprehensive coverage.

field.Other("quantity", alpacadecimal.Decimal{}).
SchemaType(map[string]string{
dialect.Postgres: "jsonb",
"postgres": "numeric",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
"postgres": "numeric",
dialect.Postgres: "numeric",

@turip
Copy link
Member Author

turip commented Apr 11, 2025

Comments will be addressed in seperate pr.

@turip turip merged commit 6ab2212 into main Apr 11, 2025
32 checks passed
@turip turip deleted the refactor/allow-single-discount-per-type branch April 11, 2025 08:04
@coderabbitai coderabbitai bot mentioned this pull request Apr 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants