Problem/Motivation

#3618741: Add a pluggable tax/invoice service seam (calculation, evidence, invoice reference), keeping tax engines out of core gave every charge record an invoice_reference field holding the tax/invoice service's identifier or URL for the issued invoice, but nothing subscriber-facing displays it. Subscribers should be able to see their billing history and reach their hosted invoices without contacting support.

Proposed resolution

A per-user invoice/charge listing in the membership portal: date, period, amount, currency, state, and a link-out where invoice_reference is a URL (or the reference text otherwise). Likely a page controller or a shipped default view over the subscription_charge entity filtered to the current user's subscriptions, access-controlled to the charge's subscription owner (plus administer subscriptions).

Remaining tasks

Decide controller vs. default view; access handler coverage for the owner-only case; kernel tests; screenshots.

User interface changes

New invoice/billing-history listing in the membership portal.

API changes

None expected.

Data model changes

None: reads the existing charge fields.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

colan created an issue. See original summary.

colan’s picture

Status: Active » Needs review

Implemented in the MR, in two commits.

Controller over shipped view — the "decide" item from the summary. A page controller avoids a Views dependency for a subscriber-facing feature, and the invoice cell (a link when the reference is a URL, plain text otherwise, empty when nothing was issued) would have needed a custom Views field plugin anyway; a controller renders it directly and kernel-tests cleanly. Sites wanting a customized listing can still build their own view — the charge entity has Views data (#3618739: Add a charge-based connector mode with a local billing cycle engine). (Or we can add a default config/optional view for this later.)

Routes and access. user/{user}/billing-history follows the manage-subscription pattern, behind the same owner-or-administrator access callback: support staff can view a member's history, and lapsed subscribers keep access to their old invoices (the access check counts inactive subscriptions). A parameterless /user/billing-history redirect feeds a new account-menu link directly under "My Membership", mirroring how that link works; the menu tree's access checking hides it from users without the permission.

The page. Newest-first, paged at 50: date, period, amount — with any refunded portion noted — state label, and the invoice link-out. Invoice documents themselves stay with whatever the tax/invoice seam (#3618741: Add a pluggable tax/invoice service seam (calculation, evidence, invoice reference), keeping tax engines out of core) points the reference at; a site wanting locally generated invoices implements that as a TaxInvoiceServiceInterface of its own and this page links to it unchanged.

Tests. New BillingHistoryTest (five scenarios): owner-only filtering, the three invoice-cell renderings, the refunded-portion display, route access (owner/admin allowed; other users and subscription-less targets denied), and the redirect. Suite is at 105 kernel tests / 1350 assertions.

Change record drafted (the new account-menu link appears on existing sites after a cache rebuild, so site builders should know it is coming and that it can be disabled at /admin/structure/menu).

  • colan committed 29469692 on 1.0.x
    Issue #3621282: Cover the billing-history page
    
    Five scenarios: owners...

  • colan committed 45042651 on 1.0.x
    Issue #3621282: List a user's billing history with invoice link-outs
    
    A...
colan’s picture

Status: Needs review » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.