Organization Approval #590

Merged
tobru merged 9 commits from feature/organization-approval into main 2026-07-03 13:16:32 +00:00
Owner
No description provided.
Add the brainstormed design and TDD implementation plan for the signup
abuse-protection feature: new organizations require staff approval before
Odoo records are created, with per-origin and per-voucher skip flags.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat: require staff approval for new organizations
All checks were successful
Tests / test (push) Successful in 1m22s
0eea16ee8e
New organizations now require staff approval before any Odoo billing
records are created, protecting signup from abuse. Organization gains an
is_approved flag (default True, so existing/programmatic creators are
unaffected); the public signup flow sets it False unless waived by
OrganizationOrigin.skip_approval or Voucher.skip_approval.

Pending orgs stash their billing input in pending_billing_data, open an
Odoo helpdesk ticket (links only, no partner), and are gated everywhere:
middleware redirects them to an "awaiting approval" dashboard and they are
hidden from the org switcher, selection, support and deep-link views. One
pending org per user.

Staff approve (replay billing -> Odoo partners + sale order + approver
chatter note, owner email) or reject (durable audit LogEntry + owner
email + delete) from /staff/. create_organization is refactored to split
shell creation from provision_billing(). Emails are best-effort and sent
via transaction.on_commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Format the pending-approval helpdesk ticket description as HTML with a
  clickable review link (Odoo description is an HTML field), mirroring the
  support form.
- Show pending organizations in the org picker, marked "Waiting for
  approval" with an hourglass icon; the selection/support/deep-link flows
  still exclude them so nothing auto-resolves into a pending org.
- Merge the pending-review queue into /staff/organizations/ via an
  "Approval" filter (Pending approval/Approved). Pending rows are badged,
  the Odoo existence check is skipped for them, and the detail page hides
  the Odoo health card. Remove the standalone pending list view/route/
  template; reject and the nav link now point at the filtered list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Render submitted billing data as a labelled definition list instead of a
  raw dict dump, resolving the stashed Odoo country/state IDs to readable
  names (Odoo-failure-safe).
- Split the approve/reject actions into clear, separate sections with
  explanatory text.
- Show the "Pending approval" badge in the page heading.
- Hide the instance billing, limit-profile/trial, and decommission cards
  for pending organizations (they have no instances or Odoo records yet).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Staff can link a pending org to an existing Odoo sale order or existing
company + billing contact at approval, avoiding duplicate Odoo records.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Staff can approve a pending organization by linking it to existing Odoo
records instead of creating fresh ones, avoiding duplicate companies,
invoice contacts, and sale orders:

- Link an existing sale order: the org reuses it (odoo_sale_order_id set,
  billing entity linked from the SO's partners); no new sale order or
  partners are created.
- Link an existing company + invoice contact: the billing entity links
  those partner IDs and approval creates a new sale order for them.

Adds staff-only Odoo search endpoints (sale orders, companies, company
invoice contacts) with live HTMX search on the approval card, an
OrganizationApproveForm to validate the choice, and Organization.approve
gains an optional link spec. BillingEntity is reused when one already
matches the invoice partner. Default approval (create from submitted data)
is unchanged. Odoo is mocked in tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Clearing a search field now clears its result list (empty query renders
  no results and no "No matches", instead of a stale list). Re-running the
  company search also resets the previously loaded invoice contacts.
- Describe what each search matches: sale-order search now also matches the
  customer name (partner_id) alongside order number and reference, with
  help text; company search notes it matches company names only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat: friendlier approval emails and resolved existing billing address
All checks were successful
Tests / test (push) Successful in 1m21s
fc99581912
Emails:
- Rewrite the approval email to be welcoming, with a working link to the
  organization dashboard, a pointer to https://docs.servala.com/, and a
  link to the getting-started first-service guide.
- Soften the rejection email wording and render the staff reason as its
  own block so multi-line comments display cleanly.
- Wrap both plain-text templates in autoescape off so reasons/names with
  apostrophes or ampersands are not turned into HTML entities.

Approval card:
- When the submitted billing choice is an existing Odoo invoice address,
  resolve and display the address (name, company, email, address) so staff
  can see what they would link, via a new get_invoice_address helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tobru force-pushed feature/organization-approval from 79ad3cfbc6
All checks were successful
Tests / test (push) Successful in 1m22s
to 73f352d2b1
All checks were successful
Tests / test (push) Successful in 1m18s
2026-07-03 13:06:01 +00:00
Compare
tobru changed title from WIP: Organization Approval to Organization Approval 2026-07-03 13:16:16 +00:00
tobru merged commit 51f1bcd5f0 into main 2026-07-03 13:16:32 +00:00
tobru deleted branch feature/organization-approval 2026-07-03 13:16:33 +00:00
Sign in to join this conversation.
No description provided.