New Pricing model with Catalog from Website #459

Merged
tobru merged 9 commits from catalog-website-sync into main 2026-04-15 07:41:17 +00:00
Owner

Summary

Replace the Odoo-centric billing model with a catalog-based billing system synced from the Servala website. This decouples the portal from Odoo for pricing data and introduces a structured, decomposed pricing model with SLA tiers, progressive discounts, and per-component pricing.

Models removed

  • OdooObjectCache - Generic cache for Odoo API responses (product IDs, pricing). No longer needed as pricing data now comes from the Servala website catalog API instead of Odoo. And it was nowhere used.
  • ServiceDefinition.billing_config (JSONField) - Free-form JSON that defined billing annotation items with productIDSource/valuePath. Replaced by the structured ServiceComponentSpec model.
  • ComputePlanAssignment.sla, .odoo_product_id, .price, .unit, .minimum_service_size - Pricing, SLA, and Odoo product references moved out of the availability junction table into dedicated catalog models. ComputePlanAssignment is now purely an availability mapping (which compute plans are offered on which control plane CRD).

Models added (in billing_catalog.py)

  • SLATier - Defines SLA levels (e.g. No SLA, BH 99.9%, 99.9% 24/7) with uptime percentage, HA replica minimums, and K8s serviceLevel value. Replaces the hardcoded SLA_CHOICES on ComputePlanAssignment.
  • ServicePricingConfig - Per-service pricing configuration: base fee, currency, billing unit, minimum units.
  • ServiceSLASurcharge - SLA-specific fixed surcharge amounts per service.
  • ComputePlanCatalogEntry - Hourly pricing for each compute plan per service, synced from the catalog. Uses DecimalField for ram_gib to support fractional values (e.g. 512Mi = 0.5 GiB).
  • StorageCatalogEntry - Per-GiB storage pricing per service.
  • ProgressiveDiscountBracket - Per-service volume discount tiers (each bracket is linked to a specific service via FK).
  • ServiceComponentSpec - Defines billing annotation structure per service (replaces billing_config JSON), including value paths, product IDs, and sizing units.
  • AdditionalCSPResource - Cloud-provider-specific resources with custom pricing (e.g. provider surcharges).
  • CatalogSyncedMixin (abstract) - Adds last_synced_at and is_stale fields with a NonStaleManager that filters out stale records.

Other notable changes

  • Service.listed field - Boolean to hide services from the catalog (e.g. services used only as supporting services).
  • ServiceInstance.sla_tier - New FK to SLATier, replacing the SLA stored on ComputePlanAssignment.
  • sync_plan_catalog management command - Syncs the full billing catalog from the Servala website API, creating/updating all catalog models and marking removed entries as stale.
  • Pricing utilities (core/utils/pricing.py) - Billing annotation builder and price calculator for the new decomposed pricing model.
  • Plan selection UI - Reworked to show pricing previews from catalog data, with support for SLA tier selection and supporting service plan filtering.
  • Invoice views removed - OrganizationInvoiceListView and related templates/URLs removed (Odoo invoice listing no longer supported).

Migrations

3 consolidated migrations (0041-0043):

  • 0041 - Creates all new billing catalog tables, removes old fields/tables (OdooObjectCache, billing_config, old ComputePlanAssignment columns), deduplicates ComputePlanAssignment rows, migrates billing_config JSON to ServiceComponentSpec rows, and adds Service.listed field
  • 0042 - Seeds the initial SLA tiers, discount brackets, and backfills sla_tier on existing ServiceInstance records
  • 0043 - Moves ProgressiveDiscountBracket from global to per-service (adds service FK) and changes ComputePlanCatalogEntry.ram_gib from integer to decimal (supports sub-GiB plans like 512Mi)

Rollout / Upgrade process

  1. Before deploying: Ensure the Servala website catalog API is available and credentials are configured:

    • SERVALA_WEBSITE_URL
    • SERVALA_WEBSITE_USERNAME
    • SERVALA_WEBSITE_PASSWORD
  2. Run migrations: just run migrate - This will:

    • Create all new billing catalog tables
    • Seed the default SLA tier ("No SLA") and discount brackets
    • Backfill sla_tier on all existing service instances
    • Deduplicate ComputePlanAssignment rows (collapse SLA variants)
    • Migrate billing_config JSON data into ServiceComponentSpec rows
    • Drop OdooObjectCache table and remove old fields
  3. Run initial catalog sync: just run sync_plan_catalog - This populates all pricing data from the website. Without this, the plan selection UI will show no pricing information.

  4. Verify: Check that the plan selection UI shows correct pricing and SLA options for existing services.

  5. Set up recurring sync: Schedule sync_plan_catalog to run periodically (e.g. via cron) to keep pricing data up to date.

## Summary Replace the Odoo-centric billing model with a catalog-based billing system synced from the Servala website. This decouples the portal from Odoo for pricing data and introduces a structured, decomposed pricing model with SLA tiers, progressive discounts, and per-component pricing. ### Models removed - **`OdooObjectCache`** - Generic cache for Odoo API responses (product IDs, pricing). No longer needed as pricing data now comes from the Servala website catalog API instead of Odoo. And it was nowhere used. - **`ServiceDefinition.billing_config`** (JSONField) - Free-form JSON that defined billing annotation items with `productIDSource`/`valuePath`. Replaced by the structured `ServiceComponentSpec` model. - **`ComputePlanAssignment.sla`**, **`.odoo_product_id`**, **`.price`**, **`.unit`**, **`.minimum_service_size`** - Pricing, SLA, and Odoo product references moved out of the availability junction table into dedicated catalog models. `ComputePlanAssignment` is now purely an availability mapping (which compute plans are offered on which control plane CRD). ### Models added (in `billing_catalog.py`) - **`SLATier`** - Defines SLA levels (e.g. No SLA, BH 99.9%, 99.9% 24/7) with uptime percentage, HA replica minimums, and K8s `serviceLevel` value. Replaces the hardcoded `SLA_CHOICES` on `ComputePlanAssignment`. - **`ServicePricingConfig`** - Per-service pricing configuration: base fee, currency, billing unit, minimum units. - **`ServiceSLASurcharge`** - SLA-specific fixed surcharge amounts per service. - **`ComputePlanCatalogEntry`** - Hourly pricing for each compute plan per service, synced from the catalog. Uses `DecimalField` for `ram_gib` to support fractional values (e.g. 512Mi = 0.5 GiB). - **`StorageCatalogEntry`** - Per-GiB storage pricing per service. - **`ProgressiveDiscountBracket`** - Per-service volume discount tiers (each bracket is linked to a specific service via FK). - **`ServiceComponentSpec`** - Defines billing annotation structure per service (replaces `billing_config` JSON), including value paths, product IDs, and sizing units. - **`AdditionalCSPResource`** - Cloud-provider-specific resources with custom pricing (e.g. provider surcharges). - **`CatalogSyncedMixin`** (abstract) - Adds `last_synced_at` and `is_stale` fields with a `NonStaleManager` that filters out stale records. ### Other notable changes - **`Service.listed`** field - Boolean to hide services from the catalog (e.g. services used only as supporting services). - **`ServiceInstance.sla_tier`** - New FK to `SLATier`, replacing the SLA stored on `ComputePlanAssignment`. - **`sync_plan_catalog` management command** - Syncs the full billing catalog from the Servala website API, creating/updating all catalog models and marking removed entries as stale. - **Pricing utilities** (`core/utils/pricing.py`) - Billing annotation builder and price calculator for the new decomposed pricing model. - **Plan selection UI** - Reworked to show pricing previews from catalog data, with support for SLA tier selection and supporting service plan filtering. - **Invoice views removed** - `OrganizationInvoiceListView` and related templates/URLs removed (Odoo invoice listing no longer supported). ### Migrations 3 consolidated migrations (0041-0043): - **0041** - Creates all new billing catalog tables, removes old fields/tables (`OdooObjectCache`, `billing_config`, old `ComputePlanAssignment` columns), deduplicates `ComputePlanAssignment` rows, migrates `billing_config` JSON to `ServiceComponentSpec` rows, and adds `Service.listed` field - **0042** - Seeds the initial SLA tiers, discount brackets, and backfills `sla_tier` on existing `ServiceInstance` records - **0043** - Moves `ProgressiveDiscountBracket` from global to per-service (adds `service` FK) and changes `ComputePlanCatalogEntry.ram_gib` from integer to decimal (supports sub-GiB plans like 512Mi) ## Rollout / Upgrade process 1. **Before deploying:** Ensure the Servala website catalog API is available and credentials are configured: - `SERVALA_WEBSITE_URL` - `SERVALA_WEBSITE_USERNAME` - `SERVALA_WEBSITE_PASSWORD` 2. **Run migrations:** `just run migrate` - This will: - Create all new billing catalog tables - Seed the default SLA tier ("No SLA") and discount brackets - Backfill `sla_tier` on all existing service instances - Deduplicate `ComputePlanAssignment` rows (collapse SLA variants) - Migrate `billing_config` JSON data into `ServiceComponentSpec` rows - Drop `OdooObjectCache` table and remove old fields 3. **Run initial catalog sync:** `just run sync_plan_catalog` - This populates all pricing data from the website. Without this, the plan selection UI will show no pricing information. 4. **Verify:** Check that the plan selection UI shows correct pricing and SLA options for existing services. 5. **Set up recurring sync:** Schedule `sync_plan_catalog` to run periodically (e.g. via cron) to keep pricing data up to date.
renovate force-pushed catalog-website-sync from 343ced743a
All checks were successful
Tests / test (push) Successful in 55s
to e8a6d76192
All checks were successful
Tests / test (push) Successful in 51s
2026-03-20 09:25:14 +00:00
Compare
renovate force-pushed catalog-website-sync from e8fa23ded6
All checks were successful
Tests / test (push) Successful in 42s
to 0d3e8f0da4
All checks were successful
Tests / test (push) Successful in 42s
2026-04-10 09:41:12 +00:00
Compare
tobru changed title from WIP: Sync functionality from catalog API to WIP: New Pricing model with Catalog from Website 2026-04-10 09:41:41 +00:00
renovate force-pushed catalog-website-sync from 1dac0ab71b
Some checks failed
Tests / test (push) Failing after 42s
to 975d169c02
All checks were successful
Tests / test (push) Successful in 42s
2026-04-13 09:21:51 +00:00
Compare
renovate force-pushed catalog-website-sync from 52f4029347
All checks were successful
Tests / test (push) Successful in 42s
to 798053d216 2026-04-14 09:03:09 +00:00
Compare
tobru changed title from WIP: New Pricing model with Catalog from Website to New Pricing model with Catalog from Website 2026-04-14 09:03:18 +00:00
tobru merged commit 09f0bc5988 into main 2026-04-15 07:41:17 +00:00
tobru deleted branch catalog-website-sync 2026-04-15 07:41:18 +00:00
Sign in to join this conversation.
No description provided.