diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1f73031b..ff1c7af5 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.2.0" + ".": "3.3.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 4de92a98..a279c92e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 103 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-2824cb456b8e3a7ce1ea34aa37a2c8e63d5b70425a5863502ffe1e1b1ef7efaf.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-25409f3b13e6d1d003e351fc18d248ecf3c5821cfde5f409a1d356e4fc917d8c.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bf05dda..f417400b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 3.3.0 (2025-02-13) + +Full Changelog: [v3.2.0...v3.3.0](https://github.com/orbcorp/orb-python/compare/v3.2.0...v3.3.0) + +### Features + +* **api:** api update ([#533](https://github.com/orbcorp/orb-python/issues/533)) ([579e4fc](https://github.com/orbcorp/orb-python/commit/579e4fcaba68a73f77fcb3a4e3be04ea904b26ee)) + + +### Chores + +* **internal:** update client tests ([#531](https://github.com/orbcorp/orb-python/issues/531)) ([e8c0abe](https://github.com/orbcorp/orb-python/commit/e8c0abe0dd656b03012cfaa2da786c03befd1f74)) + ## 3.2.0 (2025-02-11) Full Changelog: [v3.1.0...v3.2.0](https://github.com/orbcorp/orb-python/compare/v3.1.0...v3.2.0) diff --git a/pyproject.toml b/pyproject.toml index 52c7efe5..c659d8aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "orb-billing" -version = "3.2.0" +version = "3.3.0" description = "The official Python library for the orb API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/orb/_version.py b/src/orb/_version.py index e650f414..a0d396e9 100644 --- a/src/orb/_version.py +++ b/src/orb/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "orb" -__version__ = "3.2.0" # x-release-please-version +__version__ = "3.3.0" # x-release-please-version diff --git a/src/orb/resources/prices/prices.py b/src/orb/resources/prices/prices.py index b8ba0dfc..49421320 100644 --- a/src/orb/resources/prices/prices.py +++ b/src/orb/resources/prices/prices.py @@ -2486,6 +2486,97 @@ def create( """ ... + @overload + def create( + self, + *, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + cumulative_grouped_bulk_config: Dict[str, object], + currency: str, + item_id: str, + model_type: Literal["cumulative_grouped_bulk"], + name: str, + billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, + billed_in_advance: Optional[bool] | NotGiven = NOT_GIVEN, + billing_cycle_configuration: Optional[ + price_create_params.NewFloatingCumulativeGroupedBulkPriceBillingCycleConfiguration + ] + | NotGiven = NOT_GIVEN, + conversion_rate: Optional[float] | NotGiven = NOT_GIVEN, + external_price_id: Optional[str] | NotGiven = NOT_GIVEN, + fixed_price_quantity: Optional[float] | NotGiven = NOT_GIVEN, + invoice_grouping_key: Optional[str] | NotGiven = NOT_GIVEN, + invoicing_cycle_configuration: Optional[ + price_create_params.NewFloatingCumulativeGroupedBulkPriceInvoicingCycleConfiguration + ] + | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + idempotency_key: str | None = None, + ) -> Price: + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + A price created using this endpoint is always an add-on, meaning that it’s not + associated with a specific plan and can instead be individually added to + subscriptions, including subscriptions on different plans. + + An `external_price_id` can be optionally specified as an alias to allow + ergonomic interaction with prices in the Orb API. + + See the [Price resource](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. + + Args: + cadence: The cadence to bill for this price on. + + currency: An ISO 4217 currency string for which this price is billed in. + + item_id: The id of the item the plan will be associated with. + + name: The name of the price. + + billable_metric_id: The id of the billable metric for the price. Only needed if the price is + usage-based. + + billed_in_advance: If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + + billing_cycle_configuration: For custom cadence: specifies the duration of the billing period in days or + months. + + conversion_rate: The per unit conversion rate of the price currency to the invoicing currency. + + external_price_id: An alias for the price. + + fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units + applied. + + invoice_grouping_key: The property used to group this price on an invoice + + invoicing_cycle_configuration: Within each billing cycle, specifies the cadence at which invoices are produced. + If unspecified, a single invoice is produced per billing cycle. + + metadata: User-specified key/value pairs for the resource. Individual keys can be removed + by setting the value to `null`, and the entire metadata mapping can be cleared + by setting `metadata` to `null`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + + idempotency_key: Specify a custom idempotency key for this request + """ + ... + @required_args( ["cadence", "currency", "item_id", "model_type", "name", "unit_config"], ["cadence", "currency", "item_id", "model_type", "name", "package_config"], @@ -2514,6 +2605,7 @@ def create( ["cadence", "currency", "grouped_tiered_package_config", "item_id", "model_type", "name"], ["cadence", "currency", "item_id", "model_type", "name", "scalable_matrix_with_unit_pricing_config"], ["cadence", "currency", "item_id", "model_type", "name", "scalable_matrix_with_tiered_pricing_config"], + ["cadence", "cumulative_grouped_bulk_config", "currency", "item_id", "model_type", "name"], ) def create( self, @@ -2547,7 +2639,8 @@ def create( | Literal["bulk_with_proration"] | Literal["grouped_tiered_package"] | Literal["scalable_matrix_with_unit_pricing"] - | Literal["scalable_matrix_with_tiered_pricing"], + | Literal["scalable_matrix_with_tiered_pricing"] + | Literal["cumulative_grouped_bulk"], name: str, unit_config: price_create_params.NewFloatingUnitPriceUnitConfig | NotGiven = NOT_GIVEN, billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, @@ -2588,6 +2681,7 @@ def create( grouped_tiered_package_config: Dict[str, object] | NotGiven = NOT_GIVEN, scalable_matrix_with_unit_pricing_config: Dict[str, object] | NotGiven = NOT_GIVEN, scalable_matrix_with_tiered_pricing_config: Dict[str, object] | NotGiven = NOT_GIVEN, + cumulative_grouped_bulk_config: Dict[str, object] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -2643,6 +2737,7 @@ def create( "grouped_tiered_package_config": grouped_tiered_package_config, "scalable_matrix_with_unit_pricing_config": scalable_matrix_with_unit_pricing_config, "scalable_matrix_with_tiered_pricing_config": scalable_matrix_with_tiered_pricing_config, + "cumulative_grouped_bulk_config": cumulative_grouped_bulk_config, }, price_create_params.PriceCreateParams, ), @@ -5339,6 +5434,97 @@ async def create( """ ... + @overload + async def create( + self, + *, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + cumulative_grouped_bulk_config: Dict[str, object], + currency: str, + item_id: str, + model_type: Literal["cumulative_grouped_bulk"], + name: str, + billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, + billed_in_advance: Optional[bool] | NotGiven = NOT_GIVEN, + billing_cycle_configuration: Optional[ + price_create_params.NewFloatingCumulativeGroupedBulkPriceBillingCycleConfiguration + ] + | NotGiven = NOT_GIVEN, + conversion_rate: Optional[float] | NotGiven = NOT_GIVEN, + external_price_id: Optional[str] | NotGiven = NOT_GIVEN, + fixed_price_quantity: Optional[float] | NotGiven = NOT_GIVEN, + invoice_grouping_key: Optional[str] | NotGiven = NOT_GIVEN, + invoicing_cycle_configuration: Optional[ + price_create_params.NewFloatingCumulativeGroupedBulkPriceInvoicingCycleConfiguration + ] + | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + idempotency_key: str | None = None, + ) -> Price: + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + A price created using this endpoint is always an add-on, meaning that it’s not + associated with a specific plan and can instead be individually added to + subscriptions, including subscriptions on different plans. + + An `external_price_id` can be optionally specified as an alias to allow + ergonomic interaction with prices in the Orb API. + + See the [Price resource](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. + + Args: + cadence: The cadence to bill for this price on. + + currency: An ISO 4217 currency string for which this price is billed in. + + item_id: The id of the item the plan will be associated with. + + name: The name of the price. + + billable_metric_id: The id of the billable metric for the price. Only needed if the price is + usage-based. + + billed_in_advance: If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + + billing_cycle_configuration: For custom cadence: specifies the duration of the billing period in days or + months. + + conversion_rate: The per unit conversion rate of the price currency to the invoicing currency. + + external_price_id: An alias for the price. + + fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units + applied. + + invoice_grouping_key: The property used to group this price on an invoice + + invoicing_cycle_configuration: Within each billing cycle, specifies the cadence at which invoices are produced. + If unspecified, a single invoice is produced per billing cycle. + + metadata: User-specified key/value pairs for the resource. Individual keys can be removed + by setting the value to `null`, and the entire metadata mapping can be cleared + by setting `metadata` to `null`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + + idempotency_key: Specify a custom idempotency key for this request + """ + ... + @required_args( ["cadence", "currency", "item_id", "model_type", "name", "unit_config"], ["cadence", "currency", "item_id", "model_type", "name", "package_config"], @@ -5367,6 +5553,7 @@ async def create( ["cadence", "currency", "grouped_tiered_package_config", "item_id", "model_type", "name"], ["cadence", "currency", "item_id", "model_type", "name", "scalable_matrix_with_unit_pricing_config"], ["cadence", "currency", "item_id", "model_type", "name", "scalable_matrix_with_tiered_pricing_config"], + ["cadence", "cumulative_grouped_bulk_config", "currency", "item_id", "model_type", "name"], ) async def create( self, @@ -5400,7 +5587,8 @@ async def create( | Literal["bulk_with_proration"] | Literal["grouped_tiered_package"] | Literal["scalable_matrix_with_unit_pricing"] - | Literal["scalable_matrix_with_tiered_pricing"], + | Literal["scalable_matrix_with_tiered_pricing"] + | Literal["cumulative_grouped_bulk"], name: str, unit_config: price_create_params.NewFloatingUnitPriceUnitConfig | NotGiven = NOT_GIVEN, billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, @@ -5441,6 +5629,7 @@ async def create( grouped_tiered_package_config: Dict[str, object] | NotGiven = NOT_GIVEN, scalable_matrix_with_unit_pricing_config: Dict[str, object] | NotGiven = NOT_GIVEN, scalable_matrix_with_tiered_pricing_config: Dict[str, object] | NotGiven = NOT_GIVEN, + cumulative_grouped_bulk_config: Dict[str, object] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -5496,6 +5685,7 @@ async def create( "grouped_tiered_package_config": grouped_tiered_package_config, "scalable_matrix_with_unit_pricing_config": scalable_matrix_with_unit_pricing_config, "scalable_matrix_with_tiered_pricing_config": scalable_matrix_with_tiered_pricing_config, + "cumulative_grouped_bulk_config": cumulative_grouped_bulk_config, }, price_create_params.PriceCreateParams, ), diff --git a/src/orb/types/customers/cost_list_by_external_id_response.py b/src/orb/types/customers/cost_list_by_external_id_response.py index 24832e50..ff23d144 100644 --- a/src/orb/types/customers/cost_list_by_external_id_response.py +++ b/src/orb/types/customers/cost_list_by_external_id_response.py @@ -11,18 +11,10 @@ class DataPerPriceCost(BaseModel): price: Price - """ - The Price resource represents a price that can be billed on a subscription, - resulting in a charge on an invoice in the form of an invoice line item. Prices - take a quantity and determine an amount to bill. - - Orb supports a few different pricing models out of the box. Each of these models - is serialized differently in a given Price object. The model_type field - determines the key for the configuration object that is present. - - For more on the types of prices, see - [the core concepts documentation](/core-concepts#plan-and-price) - """ + """The price object""" + + price_id: str + """The price the cost is associated with""" subtotal: str """Price's contributions for the timeframe, excluding any minimums and discounts.""" diff --git a/src/orb/types/customers/cost_list_response.py b/src/orb/types/customers/cost_list_response.py index 26395c8a..48921e0f 100644 --- a/src/orb/types/customers/cost_list_response.py +++ b/src/orb/types/customers/cost_list_response.py @@ -11,18 +11,10 @@ class DataPerPriceCost(BaseModel): price: Price - """ - The Price resource represents a price that can be billed on a subscription, - resulting in a charge on an invoice in the form of an invoice line item. Prices - take a quantity and determine an amount to bill. - - Orb supports a few different pricing models out of the box. Each of these models - is serialized differently in a given Price object. The model_type field - determines the key for the configuration object that is present. - - For more on the types of prices, see - [the core concepts documentation](/core-concepts#plan-and-price) - """ + """The price object""" + + price_id: str + """The price the cost is associated with""" subtotal: str """Price's contributions for the timeframe, excluding any minimums and discounts.""" diff --git a/src/orb/types/plan_create_params.py b/src/orb/types/plan_create_params.py index 076bbf2b..7dc6c0f5 100644 --- a/src/orb/types/plan_create_params.py +++ b/src/orb/types/plan_create_params.py @@ -93,6 +93,9 @@ "PriceNewPlanScalableMatrixWithTieredPricingPrice", "PriceNewPlanScalableMatrixWithTieredPricingPriceBillingCycleConfiguration", "PriceNewPlanScalableMatrixWithTieredPricingPriceInvoicingCycleConfiguration", + "PriceNewPlanCumulativeGroupedBulkPrice", + "PriceNewPlanCumulativeGroupedBulkPriceBillingCycleConfiguration", + "PriceNewPlanCumulativeGroupedBulkPriceInvoicingCycleConfiguration", ] @@ -2249,6 +2252,89 @@ class PriceNewPlanScalableMatrixWithTieredPricingPrice(TypedDict, total=False): """ +class PriceNewPlanCumulativeGroupedBulkPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class PriceNewPlanCumulativeGroupedBulkPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class PriceNewPlanCumulativeGroupedBulkPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_bulk_config: Required[Dict[str, object]] + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_bulk"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[PriceNewPlanCumulativeGroupedBulkPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[PriceNewPlanCumulativeGroupedBulkPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + Price: TypeAlias = Union[ PriceNewPlanUnitPrice, PriceNewPlanPackagePrice, @@ -2274,4 +2360,5 @@ class PriceNewPlanScalableMatrixWithTieredPricingPrice(TypedDict, total=False): PriceNewPlanMaxGroupTieredPackagePrice, PriceNewPlanScalableMatrixWithUnitPricingPrice, PriceNewPlanScalableMatrixWithTieredPricingPrice, + PriceNewPlanCumulativeGroupedBulkPrice, ] diff --git a/src/orb/types/price.py b/src/orb/types/price.py index feac3c8d..f04b2874 100644 --- a/src/orb/types/price.py +++ b/src/orb/types/price.py @@ -270,6 +270,15 @@ "ScalableMatrixWithTieredPricingPriceMaximum", "ScalableMatrixWithTieredPricingPriceMinimum", "ScalableMatrixWithTieredPricingPriceDimensionalPriceConfiguration", + "CumulativeGroupedBulkPrice", + "CumulativeGroupedBulkPriceBillableMetric", + "CumulativeGroupedBulkPriceBillingCycleConfiguration", + "CumulativeGroupedBulkPriceCreditAllocation", + "CumulativeGroupedBulkPriceInvoicingCycleConfiguration", + "CumulativeGroupedBulkPriceItem", + "CumulativeGroupedBulkPriceMaximum", + "CumulativeGroupedBulkPriceMinimum", + "CumulativeGroupedBulkPriceDimensionalPriceConfiguration", ] @@ -3441,6 +3450,118 @@ class ScalableMatrixWithTieredPricingPrice(BaseModel): dimensional_price_configuration: Optional[ScalableMatrixWithTieredPricingPriceDimensionalPriceConfiguration] = None +class CumulativeGroupedBulkPriceBillableMetric(BaseModel): + id: str + + +class CumulativeGroupedBulkPriceBillingCycleConfiguration(BaseModel): + duration: int + + duration_unit: Literal["day", "month"] + + +class CumulativeGroupedBulkPriceCreditAllocation(BaseModel): + allows_rollover: bool + + currency: str + + +class CumulativeGroupedBulkPriceInvoicingCycleConfiguration(BaseModel): + duration: int + + duration_unit: Literal["day", "month"] + + +class CumulativeGroupedBulkPriceItem(BaseModel): + id: str + + name: str + + +class CumulativeGroupedBulkPriceMaximum(BaseModel): + applies_to_price_ids: List[str] + """List of price_ids that this maximum amount applies to. + + For plan/plan phase maximums, this can be a subset of prices. + """ + + maximum_amount: str + """Maximum amount applied""" + + +class CumulativeGroupedBulkPriceMinimum(BaseModel): + applies_to_price_ids: List[str] + """List of price_ids that this minimum amount applies to. + + For plan/plan phase minimums, this can be a subset of prices. + """ + + minimum_amount: str + """Minimum amount applied""" + + +class CumulativeGroupedBulkPriceDimensionalPriceConfiguration(BaseModel): + dimension_values: List[str] + + dimensional_price_group_id: str + + +class CumulativeGroupedBulkPrice(BaseModel): + id: str + + billable_metric: Optional[CumulativeGroupedBulkPriceBillableMetric] = None + + billing_cycle_configuration: CumulativeGroupedBulkPriceBillingCycleConfiguration + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + conversion_rate: Optional[float] = None + + created_at: datetime + + credit_allocation: Optional[CumulativeGroupedBulkPriceCreditAllocation] = None + + cumulative_grouped_bulk_config: Dict[str, object] + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoicing_cycle_configuration: Optional[CumulativeGroupedBulkPriceInvoicingCycleConfiguration] = None + + item: CumulativeGroupedBulkPriceItem + + maximum: Optional[CumulativeGroupedBulkPriceMaximum] = None + + maximum_amount: Optional[str] = None + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum: Optional[CumulativeGroupedBulkPriceMinimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["cumulative_grouped_bulk"] = FieldInfo(alias="model_type") + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price"] + + dimensional_price_configuration: Optional[CumulativeGroupedBulkPriceDimensionalPriceConfiguration] = None + + Price: TypeAlias = Annotated[ Union[ UnitPrice, @@ -3470,6 +3591,7 @@ class ScalableMatrixWithTieredPricingPrice(BaseModel): MaxGroupTieredPackagePrice, ScalableMatrixWithUnitPricingPrice, ScalableMatrixWithTieredPricingPrice, + CumulativeGroupedBulkPrice, ], PropertyInfo(discriminator="price_model_type"), ] diff --git a/src/orb/types/price_create_params.py b/src/orb/types/price_create_params.py index 88789702..2107a3cb 100644 --- a/src/orb/types/price_create_params.py +++ b/src/orb/types/price_create_params.py @@ -103,6 +103,9 @@ "NewFloatingScalableMatrixWithTieredPricingPrice", "NewFloatingScalableMatrixWithTieredPricingPriceBillingCycleConfiguration", "NewFloatingScalableMatrixWithTieredPricingPriceInvoicingCycleConfiguration", + "NewFloatingCumulativeGroupedBulkPrice", + "NewFloatingCumulativeGroupedBulkPriceBillingCycleConfiguration", + "NewFloatingCumulativeGroupedBulkPriceInvoicingCycleConfiguration", ] @@ -2410,6 +2413,86 @@ class NewFloatingScalableMatrixWithTieredPricingPriceInvoicingCycleConfiguration """The unit of billing period duration.""" +class NewFloatingCumulativeGroupedBulkPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_bulk_config: Required[Dict[str, object]] + + currency: Required[str] + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_bulk"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[NewFloatingCumulativeGroupedBulkPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewFloatingCumulativeGroupedBulkPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + +class NewFloatingCumulativeGroupedBulkPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class NewFloatingCumulativeGroupedBulkPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + PriceCreateParams: TypeAlias = Union[ NewFloatingUnitPrice, NewFloatingPackagePrice, @@ -2438,4 +2521,5 @@ class NewFloatingScalableMatrixWithTieredPricingPriceInvoicingCycleConfiguration NewFloatingGroupedTieredPackagePrice, NewFloatingScalableMatrixWithUnitPricingPrice, NewFloatingScalableMatrixWithTieredPricingPrice, + NewFloatingCumulativeGroupedBulkPrice, ] diff --git a/src/orb/types/subscription_fetch_costs_response.py b/src/orb/types/subscription_fetch_costs_response.py index 42a50f7a..64d9c0be 100644 --- a/src/orb/types/subscription_fetch_costs_response.py +++ b/src/orb/types/subscription_fetch_costs_response.py @@ -11,18 +11,10 @@ class DataPerPriceCost(BaseModel): price: Price - """ - The Price resource represents a price that can be billed on a subscription, - resulting in a charge on an invoice in the form of an invoice line item. Prices - take a quantity and determine an amount to bill. - - Orb supports a few different pricing models out of the box. Each of these models - is serialized differently in a given Price object. The model_type field - determines the key for the configuration object that is present. - - For more on the types of prices, see - [the core concepts documentation](/core-concepts#plan-and-price) - """ + """The price object""" + + price_id: str + """The price the cost is associated with""" subtotal: str """Price's contributions for the timeframe, excluding any minimums and discounts.""" diff --git a/src/orb/types/subscription_price_intervals_params.py b/src/orb/types/subscription_price_intervals_params.py index dcc68fc5..10a9e2d1 100644 --- a/src/orb/types/subscription_price_intervals_params.py +++ b/src/orb/types/subscription_price_intervals_params.py @@ -115,6 +115,9 @@ "AddPriceNewFloatingScalableMatrixWithTieredPricingPrice", "AddPriceNewFloatingScalableMatrixWithTieredPricingPriceBillingCycleConfiguration", "AddPriceNewFloatingScalableMatrixWithTieredPricingPriceInvoicingCycleConfiguration", + "AddPriceNewFloatingCumulativeGroupedBulkPrice", + "AddPriceNewFloatingCumulativeGroupedBulkPriceBillingCycleConfiguration", + "AddPriceNewFloatingCumulativeGroupedBulkPriceInvoicingCycleConfiguration", "AddAdjustment", "AddAdjustmentAdjustment", "AddAdjustmentAdjustmentNewPercentageDiscount", @@ -2520,6 +2523,86 @@ class AddPriceNewFloatingScalableMatrixWithTieredPricingPrice(TypedDict, total=F """ +class AddPriceNewFloatingCumulativeGroupedBulkPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPriceNewFloatingCumulativeGroupedBulkPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPriceNewFloatingCumulativeGroupedBulkPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_bulk_config: Required[Dict[str, object]] + + currency: Required[str] + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_bulk"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPriceNewFloatingCumulativeGroupedBulkPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[AddPriceNewFloatingCumulativeGroupedBulkPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + AddPrice: TypeAlias = Union[ AddPriceNewFloatingUnitPrice, AddPriceNewFloatingPackagePrice, @@ -2548,6 +2631,7 @@ class AddPriceNewFloatingScalableMatrixWithTieredPricingPrice(TypedDict, total=F AddPriceNewFloatingGroupedTieredPackagePrice, AddPriceNewFloatingScalableMatrixWithUnitPricingPrice, AddPriceNewFloatingScalableMatrixWithTieredPricingPrice, + AddPriceNewFloatingCumulativeGroupedBulkPrice, ] diff --git a/tests/api_resources/test_prices.py b/tests/api_resources/test_prices.py index 096edc04..41b706cf 100644 --- a/tests/api_resources/test_prices.py +++ b/tests/api_resources/test_prices.py @@ -2158,6 +2158,79 @@ def test_streaming_response_create_overload_27(self, client: Orb) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_create_overload_28(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + cumulative_grouped_bulk_config={"foo": "bar"}, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_28(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + cumulative_grouped_bulk_config={"foo": "bar"}, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="invoice_grouping_key", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_28(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + cumulative_grouped_bulk_config={"foo": "bar"}, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", + name="Annual fee", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + price = response.parse() + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_28(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + cumulative_grouped_bulk_config={"foo": "bar"}, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", + name="Annual fee", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + price = response.parse() + assert_matches_type(Price, price, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_update(self, client: Orb) -> None: price = client.prices.update( @@ -4474,6 +4547,79 @@ async def test_streaming_response_create_overload_27(self, async_client: AsyncOr assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_create_overload_28(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + cumulative_grouped_bulk_config={"foo": "bar"}, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_28(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + cumulative_grouped_bulk_config={"foo": "bar"}, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="invoice_grouping_key", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_28(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + cumulative_grouped_bulk_config={"foo": "bar"}, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", + name="Annual fee", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + price = response.parse() + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_28(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + cumulative_grouped_bulk_config={"foo": "bar"}, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", + name="Annual fee", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + price = await response.parse() + assert_matches_type(Price, price, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_update(self, async_client: AsyncOrb) -> None: price = await async_client.prices.update( diff --git a/tests/test_client.py b/tests/test_client.py index 432310e0..fbcbf29a 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -23,10 +23,12 @@ from orb import Orb, AsyncOrb, APIResponseValidationError from orb._types import Omit +from orb._utils import maybe_transform from orb._models import BaseModel, FinalRequestOptions from orb._constants import RAW_RESPONSE_HEADER from orb._exceptions import OrbError, APIStatusError, APITimeoutError, APIResponseValidationError from orb._base_client import DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, BaseClient, make_request_options +from orb.types.customer_create_params import CustomerCreateParams from .utils import update_env @@ -733,7 +735,12 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> No with pytest.raises(APITimeoutError): self.client.post( "/customers", - body=cast(object, dict(email="example-customer@withorb.com", name="My Customer")), + body=cast( + object, + maybe_transform( + dict(email="example-customer@withorb.com", name="My Customer"), CustomerCreateParams + ), + ), cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, ) @@ -748,7 +755,12 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> Non with pytest.raises(APIStatusError): self.client.post( "/customers", - body=cast(object, dict(email="example-customer@withorb.com", name="My Customer")), + body=cast( + object, + maybe_transform( + dict(email="example-customer@withorb.com", name="My Customer"), CustomerCreateParams + ), + ), cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, ) @@ -1555,7 +1567,12 @@ async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) with pytest.raises(APITimeoutError): await self.client.post( "/customers", - body=cast(object, dict(email="example-customer@withorb.com", name="My Customer")), + body=cast( + object, + maybe_transform( + dict(email="example-customer@withorb.com", name="My Customer"), CustomerCreateParams + ), + ), cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, ) @@ -1570,7 +1587,12 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) with pytest.raises(APIStatusError): await self.client.post( "/customers", - body=cast(object, dict(email="example-customer@withorb.com", name="My Customer")), + body=cast( + object, + maybe_transform( + dict(email="example-customer@withorb.com", name="My Customer"), CustomerCreateParams + ), + ), cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, )