feat(invoicing-period): surface lightweight customer membership on non-active views (#371)

## Summary

Customer indicator chips (e.g. *Faktura pr. ordre*, *Fastpris*,
*Tankrengøring*) currently only render on the matching view tab because
the period paged response strips customer data from every non-active
view bucket. The front-end therefore cannot determine which other
categories a customer belongs to from the *Alle* tab.

This change projects a deduplicated lightweight customer marker
`{customer_number, membership_only: true}` onto every non-active view
bucket in `applyPeriodPagination`. The active bucket still carries full
customer cards so paginated full-data output, type_counts and
type_totals are unchanged. Filters, search, sort, flag tab and workflow
filters upstream of the membership projection make the non-active
membership set match the active-bucket semantics for the same request.

## Contract change (openapi.yaml)

* New schema `InvoicingPeriodCustomerMembership` with `{
customer_number, membership_only: true }` and `additionalProperties:
false`.
* `InvoicingPeriodData.types[view].items` is now a `oneOf` of
`InvoicingPeriodCustomer` and `InvoicingPeriodCustomerMembership`.
* `InvoicingPeriodCustomer.required` relaxed to `customer_number` only
(other fields are now reported per-view).

## Implementation

* New helper `summarizeNonActiveCustomerMemberships()` projects +
deduplicates by `customer_number`.
* Pagination emits full cards for the active bucket and lightweight
memberships everywhere else.

## Tests

* Updated existing `fixed_pricing` assertion to include the membership
marker.
* Added four new tests:
* default projection across all view buckets (with explicit dedup
assertion),
  * search filter propagation,
  * flag-tab filter propagation,
  * single-customer active-bucket edge case.

All 15 `InvoicingPeriodPaginationTest` tests pass locally (158
assertions).

🤖 Generated by [OpenHands](https://docs.openhands.dev/) on behalf of
copenhagentruckwash.

Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
Jeppe B
2026-08-13 15:16:25 +02:00
committed by GitHub
co-authored by openhands
parent 0dea2f0b76
commit 51e5c2ed01
3 changed files with 295 additions and 3 deletions
+25 -2
View File
@@ -18548,11 +18548,13 @@ components:
additionalProperties:
type: array
items:
$ref: '#/components/schemas/InvoicingPeriodCustomer'
oneOf:
- $ref: '#/components/schemas/InvoicingPeriodCustomer'
- $ref: '#/components/schemas/InvoicingPeriodCustomerMembership'
InvoicingPeriodCustomer:
type: object
required: [customer_number, customer_name, transactions, invoice_collections]
required: [customer_number]
additionalProperties: true
properties:
customer_number:
@@ -18568,6 +18570,27 @@ components:
items:
$ref: '#/components/schemas/InvoicingPeriodInvoiceCollection'
InvoicingPeriodCustomerMembership:
type: object
description: >-
Lightweight customer marker returned for every non-active view
bucket of the period response. Used by the front-end to render
category indicator chips (e.g. "Faktura pr. ordre") regardless of
which tab the user is currently looking at. Full customer-card
data (transactions, invoice collections, queue, draft, meta)
is intentionally omitted for non-active buckets; see
InvoicingPeriodCustomer for the shape returned for the active
bucket.
additionalProperties: false
required: [customer_number, membership_only]
properties:
customer_number:
type: integer
minimum: 1
membership_only:
type: boolean
enum: [true]
InvoicingPeriodTransaction:
type: object
required: [id, booked, invoice_state]