Skip to content

Customer Portal

The Customer Portal is the self-service site customers and reseller sub-accounts use to manage their own account, separate from the operator-facing admin app. It typically runs at portal.<domain> (for example portal.telecloud.co.za or portal.moviemagic.cc) and lets a signed-in customer see their account balance, invoices, subscriptions and call/airtime usage, download statements and invoice PDFs, request or cancel services, and get help — all scoped strictly to the organisation(s) their login is linked to.

Resellers get an extra layer on top: a reseller login can also manage its own end-users ("My Customers") and log into the portal as one of them for support purposes.

What you can do

  • Account Overview — a summary dashboard showing account name, current balance, currency, active/suspended service counts by type, recent invoices, and (for voice customers) live airtime/wallet balance or unlimited-plan usage pulled straight from the PBX.
  • My Invoices — a read-only list of the account's sales invoices (number, customer, date, amount).
  • My Balance — the account's current balance-forward figure and currency.
  • Statement — a full Statement of Account: invoices, payments, credit notes, refunds and journal entries merged into one dated ledger with a running balance, matching the same figure the balance card shows. Each line can open the underlying invoice or payment PDF, and the whole statement can be downloaded as a branded PDF.
  • My Subscriptions — every active/suspended/cancelled service the account has, plus any "Pending Activation" orders not yet provisioned. From here a customer can open a service's management panel (hosting control panel SSO, PBX call-flow editor for phone numbers, IPTV/SMS/newsletter panels), resend the service's setup email, or self-cancel/reduce a subscription.
  • Activations — the account's own order/activation history (any status), with a self-service "Process" action to complete a still-pending order.
  • Voice usage & airtime recommendation — call volume/minutes/spend by month for the account's PBX domain(s), current airtime wallet or unlimited-plan status, and a recommended monthly airtime top-up based on recent call spend.
  • Make a Payment — a one-click link to the most recent payable invoice's public "Pay Now" page.
  • Visit Webstore — a link (with single sign-on) to the public storefront that fronts the account's books site.
  • Contact Us — a support form that emails the central helpdesk inbox, tagged with the customer's name, org and originating site.
  • My Customers (resellers only) — a reseller's own end-user/sub-account list, with the ability to create a new end-user, edit one, or log into the portal as them.

Common tasks

  1. Check what you owe — open the Overview to see the current account balance at a glance, or open My Balance / Statement for the exact figure and how it was arrived at.
  2. View or download a Statement of Account — go to Statement, review the dated list of charges and payments with running balance, then use View PDF in the toolbar to get the branded PDF version.
  3. Pay an outstanding invoice — use the Make a Payment button (Overview / account menu); it jumps straight to the newest invoice that is actually payable right now.
  4. See or manage a service — open My Subscriptions, find the row, and use Manage Service to open that service's control panel (e.g. hosting SiteWorx, PBX phone-number/call-flow editor) in a new tab or modal.
  5. Cancel or reduce a subscription — from My Subscriptions, use the row's Cancel Subscription action; cancellation is scheduled for the end of the current billing month (or, for quantity-based services like airtime blocks, you can reduce the quantity instead of cancelling the whole line).
  6. Finish a pending order — open Activations, find the row with status "Pending", and use Process to complete provisioning.

Data model

The portal identity layer and the commercial ("books") data live in different places and are joined at read time:

  • Tenant — the portal login's organisation record (name, id); resolved from the signed-in session / org switcher.
  • AccCustomer — the billing-side customer record on the books site; linked to a portal login via portal_tenant_id, and to a PBX domain via portal_domain_uuid. One portal login can be linked to more than one AccCustomer.
  • ResellerUser (legacy) / reseller end-user AccCustomer rows (customer_group="Reseller User") — a reseller's own sub-accounts, linked to their own tenant via portal_tenant_id and to their subscriptions via reseller_user_id.
  • Subscription — a billable service line (product, service_type, provision_type, domain/reference, qty, status); the source for My Subscriptions, service counts, phone-number listings and airtime quantities.
  • Activation — an order that hasn't yet been provisioned into a Subscription; surfaces as "Pending Activation" until processed.
  • AccSalesInvoice — sales invoices/credit notes; source for My Invoices and the Statement.
  • AccPaymentEntry — payments/refunds; source for the Statement.
  • GLEntry — general-ledger movements against the customer's receivable account; the single source of truth the Statement and the account balance are built from.
  • Balance — the account's aggregated balance-forward row (My Balance card).
  • Storefront — the books site's public webstore record (domain), used for the "Visit Webstore" link.

Configuration & integrations

  • A site is turned into a customer portal by setting is_customer_portal_site: true in its site_config.json. This blocks it from installing operator-only apps (accounting, debtors, buying, CRM) and only allows the portal app.
  • A federated portal site declares parent_site (e.g. portal → tc, mm_portal → mm) — its own database holds only identity (tenants, users, memberships), and every commercial read (app.core.site.books_site_for) is made cross-database against the parent's books site. A self-contained customer-facing site (e.g. mm) is its own books site.
  • The portal grids are registered on sites = {"portal", "mm", "mm_portal"}; a site must be in this set (both the portal-facing site and the site whose database backs it) or its /g/portal-* menu entries disappear.
  • FusionPBX — resolved via erp_credentials.resolve_provider(db, "fusionpbx"); used for live voice wallet/unlimited-plan balances (GET /api/v1/balance/summary) and call-history stats (GET /api/v1/call-history). Best-effort — an unconfigured or unreachable PBX simply blanks the airtime/usage sections rather than breaking the page.
  • Axxess — used to fetch live data-usage summaries for lte_account subscriptions on My Subscriptions.
  • Mailer — the Contact Us form and subscription setup-email resend go through app.services.mailer / app.services.portal_org_smtp; Contact Us always targets a fixed helpdesk inbox (helpdesk@telecloud.co.za), not the site's own support email.
  • Impersonation — a reseller's "Log into Service Portal" action mints a single-use login via app.services.impersonation, provisioning the end-user's portal login on first use.

Account scoping

Every portal endpoint and grid scopes to the signed-in login's active organisation, resolved as a dashless tenant UUID from the X-Tenant-ID org-switcher header (falling back to the session's own tenant_uuid). A superuser who selects "All organizations" (X-Tenant-ID: all, or none) is the one exception: they see a platform-wide Operations Center view instead of any single customer's data, so a real customer's numbers are never presented under a "Superadmin" heading. A reseller end-user with no AccCustomer of its own is scoped by ResellerUser.portal_tenant_id instead, and only ever sees its own subscriptions/activations — never its parent reseller's full book.

API reference

Portal-specific endpoints live under /portal (app/api/portal.py):

Method & pathPurpose
GET /portal/summaryAccount Overview aggregate: balance, currency, service counts, unlocked service-portal apps, recent invoices, phone numbers, and live airtime/unlimited-plan state. Returns a platform-wide view for a superadmin on "All organizations".
GET /portal/voice-usageMonthly call-history stats and airtime wallet/unlimited status for the account's PBX domain(s), plus a recommended monthly airtime spend based on recent usage.
GET /portal/webstoreThe public storefront URL for the account's books site (for "Visit Webstore" / SSO order links), or null if none is published.
GET /portal/pay-linkThe "Make a Payment" link — the public pay page for the most recent invoice that's actually payable, or null.
GET /portal/document-pdf/{voucher_type}/{voucher_id}Returns a base64 PDF for one invoice (acc_sales_invoice) or payment (acc_payment_entry) belonging to the caller's own linked customer(s).
POST /portal/contactSubmits the Contact Us form; emails the central helpdesk inbox.

Everything else (invoices, balances, statement, subscriptions, activations, reseller end-users) is served through the generic grid CRUD engine at /g/{slug} (app/grids/portal.py), all self-scoping to the signed-in login's linked account(s) and read-only except for a small set of guarded row actions:

Grid slugDataNotable actions
portal-invoicesMy Invoices
portal-balancesMy Balance
portal-statementStatement of AccountView PDF (branded Statement PDF)
portal-subscriptionsMy Subscriptions (+ pending activations)Manage Service, Email Setup Instructions, Cancel Subscription
portal-activationsActivations (own orders)Process
portal-reseller-usersMy Customers (reseller end-users)New, Edit, Log into Service Portal

All grid providers and row actions independently re-verify that the row belongs to the caller's own tenant/customer before returning data, since these grids bypass the normal staff permission checks (customer_safe).

Lubb ERP Documentation