Accrue.Entitlements.Admin (accrue v1.4.0)

Copy Markdown View Source

Internal read-only diagnostic seam for the accrue_admin entitlements tab (ENT-11).

NOT a public gate API — there is no boolean entitled?-style surface here (Phase 123 D-07 fetch_entitled/2 stays deferred). This module answers the operator question "what does the resolver currently grant this customer, and what entitling price_ids is it silently discarding?" by returning a {resolved, unmapped_price_ids} pair — never a grant/deny decision.

One-way dependency

admin → billing/entitlements core, never the reverse. Nothing under Accrue.Billing or the resolver references this module; it only reads through the resolver's SSOT fold.

Resolver scope

Hard-codes the default Accrue.Entitlements.Resolver.LocalMap resolver. The diagnostic re-derives the structurally-discarded unmapped drift, which is a property of the local plan→price_id catalog; custom resolvers are out of scope for this read-only diagnostic.

Why a {resolved, unmapped} pair

The resolver drops unmapped entitling price_ids under :deny (Accrue.Entitlements.Resolver.LocalMap handle_unmapped/3), so the resolved map can NEVER surface drift. unmapped_entitling_price_ids/1 re-reads the customer's entitling items independently and returns only the price_ids the catalog does not map — the operator's drift signal.

Summary

Functions

Returns {resolved, unmapped_price_ids} for customer

Functions

resolve_for_customer(customer)

@spec resolve_for_customer(Accrue.Billing.Customer.t()) ::
  {resolved :: map(), unmapped_price_ids :: [String.t()]}

Returns {resolved, unmapped_price_ids} for customer:

  • resolved — the resolver's SSOT fold (active_plans, features, quantities, and the grace sets), reusing LocalMap.fold_for_customer/1 (no re-implemented fold), and
  • unmapped_price_ids — the entitling price_ids the resolver structurally discards under :deny, via LocalMap.unmapped_entitling_price_ids/1.