docs(billing): handoff update — sub-project #2 complete (2a/2d shipped, 2b/2c code-complete)
This commit is contained in:
@@ -78,3 +78,51 @@ start with?**
|
|||||||
Cut each new feature branch from `main`, and land it before starting the next. For any
|
Cut each new feature branch from `main`, and land it before starting the next. For any
|
||||||
cross-branch git surgery, use a **throwaway `git worktree`** — never switch the shared
|
cross-branch git surgery, use a **throwaway `git worktree`** — never switch the shared
|
||||||
working dir's branch, because a concurrent session may be working on it.
|
working dir's branch, because a concurrent session may be working on it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## UPDATE — sub-project #2 complete (2026-05-27, later session)
|
||||||
|
|
||||||
|
All four chunks of #2 are now built. The brainstorm "which slice" question resolved to
|
||||||
|
2a-first; everything else followed.
|
||||||
|
|
||||||
|
**Done + on `main` in `Odoo-Modules` (fully tested on odoo-trial, suite `FCB_EXIT=0`):**
|
||||||
|
- **2a — importer** (`fusion.billing.import.wizard`): read-only `psycopg2` reader split
|
||||||
|
from pure-Odoo writes; users→partners+links, plans→`cpu_seconds` charge catalog
|
||||||
|
(`plan_id` NULL), deployments→one **draft shadow** `sale.order` each with the flat price.
|
||||||
|
Shadow-safe by construction (draft + no token + NULL `plan_id`). Idempotent, dry-run,
|
||||||
|
Test-Connection guard, README runbook.
|
||||||
|
- **2d — reconciliation** (`fusion.billing.reconciliation`): `_compute_reconciliation` +
|
||||||
|
`_reconcile_rows` (Odoo flat+overage vs NexaCloud actual, status match/delta), reader for
|
||||||
|
NexaCloud usage+invoice actuals, "Run Reconciliation" button. **Upsert key is
|
||||||
|
`(service, external_subscription_id, period)`** — per subscription, so a customer with
|
||||||
|
two deployments doesn't collide.
|
||||||
|
- **/usage enabler**: `_api_record_usage` resolves a subscription by the source app's own
|
||||||
|
id (`x_fc_nexacloud_subscription_id`) so NexaCloud can push against shadow subs.
|
||||||
|
- Core-engine bug fixed in passing: `charge.price_per_unit` is now `Float(16,6)` and
|
||||||
|
`_compute_billable` keeps 6-dp precision (was `Monetary`/cent-rounded → would under-bill
|
||||||
|
sub-cent rates and drift from NexaCloud's 4-dp amounts).
|
||||||
|
|
||||||
|
**Code-complete in `Nexa-Cloud` (feature-flagged, NOT deployed, NOT integration-tested):**
|
||||||
|
- **2b — usage push**: `services/odoo_billing_client.py` + a hook in `usage_metering.py`
|
||||||
|
posting cpu-seconds to Odoo `/usage`. **2c — control loop**:
|
||||||
|
`routers/odoo_billing.py` (`POST /api/v1/billing/webhooks/central`, HMAC-verified) +
|
||||||
|
`services/odoo_billing_integration.py` (suspend/restore/deprovision). All INERT unless
|
||||||
|
`ODOO_BILLING_ENABLED`. Implemented as NEW modules + edits to clean files only —
|
||||||
|
NexaCloud `main` had concurrent **Cursor uncommitted WIP** (`routers/billing.py`,
|
||||||
|
`scheduler.py`, `stripe_service.py`, `models/billing.py`, …) which was deliberately not
|
||||||
|
touched. Commits: `94542ec` + `956abb2` (only my files staged).
|
||||||
|
|
||||||
|
**Remaining before go-live (gated on infra / ops you do):**
|
||||||
|
1. Grant the read-only DSN (`fusion_billing.nexacloud_dsn`) — see the module README — then
|
||||||
|
Test Connection → dry-run import → review → real import.
|
||||||
|
2. Run a dual-run cycle (Run Reconciliation), confirm all rows `match`.
|
||||||
|
3. **2c needs the Odoo side to actually EMIT** `invoice.payment_failed` /
|
||||||
|
`payment_succeeded` / `subscription.terminated` webhooks with `deployment_id` in the
|
||||||
|
payload — that emission isn't wired yet (it belongs to the live billing flow). The
|
||||||
|
NexaCloud receiver is built to that contract; confirm the payload shape when wiring it.
|
||||||
|
4. Integration-test + deploy the NexaCloud changes (no test harness in that repo).
|
||||||
|
5. The flip: set `charge.plan_id`, attach Stripe tokens, confirm the shadow subs.
|
||||||
|
|
||||||
|
Specs/plans: `specs/2026-05-27-nexacloud-billing-importer-design.md`,
|
||||||
|
`specs/2026-05-27-nexacloud-reconciliation-design.md`, and the matching plans.
|
||||||
|
|||||||
Reference in New Issue
Block a user