from __future__ import annotations from typing import Any from .provider_publication import ( ProviderMappedArtifact, ProviderPublicationPackage, PublicationBundle, PublishableCommitment, PublishableConfiguration, PublishableMeter, PublishablePrice, ) def _lookup_key(*parts: str) -> str: return "--".join( part.replace(":", "-").replace("_", "-") for part in parts if part ) def _stripe_interval(value: str | None) -> str | None: if value is None: return None normalized = value.lower() if normalized in {"monthly", "month"}: return "month" if normalized in {"yearly", "annual", "year"}: return "year" return normalized def _stripe_hints(bundle: PublicationBundle) -> dict[str, Any]: return dict(bundle.provider_hints.get("stripe", {})) def _product_provider_id(bundle: PublicationBundle) -> str: hints = _stripe_hints(bundle) return hints.get("product_lookup_key") or _lookup_key("product", bundle.product.product_id) def _meter_provider_id(bundle: PublicationBundle, meter: PublishableMeter) -> str: hints = _stripe_hints(bundle) if hints.get("meter_name") and len(bundle.meters) == 1: return str(hints["meter_name"]) return _lookup_key("meter", bundle.model_id, meter.meter_id) def _product_artifact(bundle: PublicationBundle) -> ProviderMappedArtifact: hints = _stripe_hints(bundle) return ProviderMappedArtifact( provider="stripe", source_key=bundle.product.key, source_kind="product", provider_id=_product_provider_id(bundle), provider_object_type="product", mapping_status="exact", payload={ "lookup_key": _product_provider_id(bundle), "name": bundle.product.name, "description": bundle.product.description, "active": bundle.product.active, "metadata": { **bundle.product.metadata, "collection_method": hints.get("collection_method", "charge_automatically"), "source_of_truth": "adaptive-pricing", }, }, metadata={"model_id": bundle.model_id}, notes=("Stripe product mapping is direct for catalog identity and metadata.",), ) def _meter_artifact(bundle: PublicationBundle, meter: PublishableMeter) -> ProviderMappedArtifact: provider_id = _meter_provider_id(bundle, meter) return ProviderMappedArtifact( provider="stripe", source_key=meter.key, source_kind="meter", provider_id=provider_id, provider_object_type="billing_meter", mapping_status="exact", payload={ "lookup_key": provider_id, "display_name": meter.name, "event_name": meter.event_name, "default_aggregation": {"formula": meter.aggregation}, "unit_label": meter.unit, "metadata": { **meter.metadata, "source_of_truth": "adaptive-pricing", }, }, metadata={"model_id": bundle.model_id}, notes=("Stripe meter mapping is direct for metered usage identifiers.",), ) def _fixed_price_payload(bundle: PublicationBundle, price: PublishablePrice) -> dict[str, Any]: payload = { "lookup_key": _lookup_key("price", bundle.model_id, price.component_id), "product": _product_provider_id(bundle), "currency": price.currency.lower(), "nickname": price.label, "unit_amount_decimal": str(price.amount or "0"), "metadata": { **price.metadata, "source_of_truth": "adaptive-pricing", }, } if price.billing_treatment != "one_time" and price.cadence: payload["recurring"] = {"interval": _stripe_interval(price.cadence)} return payload def _discount_artifact(bundle: PublicationBundle, price: PublishablePrice) -> ProviderMappedArtifact: provider_id = _lookup_key("coupon", bundle.model_id, price.component_id) return ProviderMappedArtifact( provider="stripe", source_key=price.key, source_kind="price", provider_id=provider_id, provider_object_type="coupon", mapping_status="approximate", payload={ "lookup_key": provider_id, "amount_off_decimal": str(abs(price.amount or 0)), "currency": price.currency.lower(), "name": price.label, "metadata": { **price.metadata, "source_of_truth": "adaptive-pricing", }, }, metadata={"model_id": bundle.model_id}, notes=( "Stripe coupons approximate discount components because attachment to subscriptions and eligibility rules lives outside the price object.", ), ) def _usage_price_artifact( bundle: PublicationBundle, price: PublishablePrice, ) -> ProviderMappedArtifact: provider_id = _lookup_key("price", bundle.model_id, price.component_id) if price.meter_key is None or price.unit_price is None: return ProviderMappedArtifact( provider="stripe", source_key=price.key, source_kind="price", provider_id=provider_id, provider_object_type="price", mapping_status="unsupported", payload={ "lookup_key": provider_id, "reason": "usage component lacks a billable per-unit price or mapped meter", }, metadata={"model_id": bundle.model_id}, notes=( "Stripe publication cannot create a metered price without both a meter and a per-unit charge.", ), ) meter_provider_id = _lookup_key("meter", bundle.model_id, price.component_id) if len(bundle.meters) == 1: meter_provider_id = _meter_provider_id(bundle, bundle.meters[0]) status = "approximate" if price.included_units not in (None, 0) else "exact" notes = [ "Stripe metered price mapping is direct for per-unit overage billing.", ] if status == "approximate": notes.append( "Included usage allowance requires supplemental credits, invoice adjustments, or custom entitlement logic outside the Stripe price object." ) return ProviderMappedArtifact( provider="stripe", source_key=price.key, source_kind="price", provider_id=provider_id, provider_object_type="price", mapping_status=status, payload={ "lookup_key": provider_id, "product": _product_provider_id(bundle), "currency": price.currency.lower(), "nickname": price.label, "billing_scheme": "per_unit", "unit_amount_decimal": str(price.unit_price), "recurring": { "interval": _stripe_interval(price.cadence) or "month", "usage_type": "metered", }, "meter": meter_provider_id, "metadata": { **price.metadata, "included_units": str(price.included_units) if price.included_units is not None else None, "source_of_truth": "adaptive-pricing", }, }, metadata={"model_id": bundle.model_id}, notes=tuple(notes), ) def _price_artifact(bundle: PublicationBundle, price: PublishablePrice) -> ProviderMappedArtifact: provider_id = _lookup_key("price", bundle.model_id, price.component_id) if price.component_kind == "usage": return _usage_price_artifact(bundle, price) if price.component_kind == "discount": return _discount_artifact(bundle, price) return ProviderMappedArtifact( provider="stripe", source_key=price.key, source_kind="price", provider_id=provider_id, provider_object_type="price", mapping_status="exact", payload=_fixed_price_payload(bundle, price), metadata={"model_id": bundle.model_id}, notes=("Stripe price mapping is direct for fixed recurring or one-time charges.",), ) def _commitment_artifact( bundle: PublicationBundle, commitment: PublishableCommitment, ) -> ProviderMappedArtifact: provider_id = _lookup_key("commitment", bundle.model_id, commitment.commitment_id) if commitment.kind == "contract_duration": return ProviderMappedArtifact( provider="stripe", source_key=commitment.key, source_kind="commitment", provider_id=provider_id, provider_object_type="metadata_binding", mapping_status="approximate", payload={ "lookup_key": provider_id, "metadata": { **commitment.metadata, "contract_duration_value": commitment.value, "contract_duration_unit": commitment.unit, }, }, metadata={"model_id": bundle.model_id}, notes=( "Stripe can store contract duration metadata, but enforcement still relies on subscription schedule policy or external contract workflow.", ), ) return ProviderMappedArtifact( provider="stripe", source_key=commitment.key, source_kind="commitment", provider_id=provider_id, provider_object_type="metadata_binding", mapping_status="unsupported", payload={ "lookup_key": provider_id, "kind": commitment.kind, "value": commitment.value, "unit": commitment.unit, }, metadata={"model_id": bundle.model_id}, notes=( "Stripe metadata alone cannot enforce this commitment semantics; it remains an internal pricing and contract artifact.", ), ) def _configuration_artifact( bundle: PublicationBundle, configuration: PublishableConfiguration, ) -> ProviderMappedArtifact: provider_id = _lookup_key("configuration", configuration.configuration_id) return ProviderMappedArtifact( provider="stripe", source_key=configuration.key, source_kind="configuration", provider_id=provider_id, provider_object_type="metadata_binding", mapping_status="approximate", payload={ "lookup_key": provider_id, "metadata": { **configuration.metadata, "configuration_id": configuration.configuration_id, "segment": configuration.segment, "price_keys": list(configuration.price_keys), "commitment_keys": list(configuration.commitment_keys), }, }, metadata={"model_id": bundle.model_id}, notes=( "Customer or default pricing configurations can be recorded in Stripe metadata, but they are not first-class Stripe catalog objects.", ), ) def map_bundle_to_stripe(bundle: PublicationBundle) -> ProviderPublicationPackage: artifacts: list[ProviderMappedArtifact] = [_product_artifact(bundle)] artifacts.extend(_meter_artifact(bundle, meter) for meter in bundle.meters) artifacts.extend(_price_artifact(bundle, price) for price in bundle.prices) artifacts.extend(_commitment_artifact(bundle, commitment) for commitment in bundle.commitments) artifacts.extend( _configuration_artifact(bundle, configuration) for configuration in bundle.configurations ) notes = [ "Stripe remains an execution backend; adaptive-pricing stays the source of truth.", "Exact mappings create publishable Stripe shadow artifacts; approximate mappings require supplemental operational logic.", ] if _stripe_hints(bundle).get("metered_usage_strategy") == "future_adapter": notes.append( "The pricing model declares a future metered-usage strategy hint, so Stripe publication keeps the usage allowance semantics descriptive rather than executable." ) return ProviderPublicationPackage( provider="stripe", bundle_id=bundle.bundle_id, model_id=bundle.model_id, model_name=bundle.model_name, artifacts=tuple(artifacts), notes=tuple(notes), )