Skip to content

feat(products): add rate card GraphQL - #5707

Merged
rsempe merged 7 commits into
mainfrom
products-and-plans-rate-cards
Aug 12, 2026
Merged

feat(products): add rate card GraphQL#5707
rsempe merged 7 commits into
mainfrom
products-and-plans-rate-cards

Conversation

@rsempe

@rsempe rsempe commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Context

Rate cards are where pricing lives: one card prices exactly one product, or one filter slice of it. Rates sit on the card as an effective-dated timeline, so a price change is an append rather than an edit.

Description

  • Types, enums and inputs for RateCard (billing timing, regroup), with mutations and resolvers behind the rate_cards:* permissions.
  • List fields (ratesCount, the attachment lock signal) batched through the dataloader sources.
  • Rate cards are exposed without nesting their rates: rates are fetched through their own query (rateCardRates), keyed by card.
  • regroup_paid_fees is exposed as a nullable enum where a null input means none (the column is NOT NULL).
  • Rate card added to the activity-log resource union.

@rsempe rsempe changed the title feat(products): add rate card services and GraphQL mutations feat(products): Add rate card services and GraphQL mutations Jun 12, 2026
@rsempe
rsempe force-pushed the products-and-plans-rate-cards branch 2 times, most recently from 8760132 to 5d5175e Compare June 12, 2026 09:01
@rsempe
rsempe force-pushed the products-and-plans-api branch from 5b13f98 to c42f976 Compare June 12, 2026 09:24
@rsempe
rsempe force-pushed the products-and-plans-rate-cards branch from 5d5175e to 28bb3ac Compare June 12, 2026 09:24
@rsempe
rsempe force-pushed the products-and-plans-api branch from c42f976 to 349bc65 Compare June 18, 2026 10:21
@rsempe
rsempe force-pushed the products-and-plans-rate-cards branch from 28bb3ac to 77426a7 Compare June 18, 2026 10:21
@rsempe
rsempe force-pushed the products-and-plans-api branch from 349bc65 to 78da4f2 Compare June 18, 2026 11:49
@rsempe
rsempe force-pushed the products-and-plans-rate-cards branch 2 times, most recently from c0227cc to f03063e Compare June 18, 2026 12:00
@rsempe
rsempe force-pushed the products-and-plans-api branch from 78da4f2 to 7b15c60 Compare June 18, 2026 12:00
@rsempe
rsempe force-pushed the products-and-plans-rate-cards branch from f03063e to ef03551 Compare June 18, 2026 12:36
@rsempe
rsempe force-pushed the products-and-plans-api branch 2 times, most recently from 0961809 to ac0e228 Compare June 18, 2026 12:39
@rsempe
rsempe force-pushed the products-and-plans-rate-cards branch 3 times, most recently from 2f53905 to 8c25fb7 Compare June 22, 2026 13:17
@rsempe
rsempe force-pushed the products-and-plans-api branch from e5b933c to bba2f03 Compare June 22, 2026 13:17
@rsempe
rsempe force-pushed the products-and-plans-rate-cards branch from 8c25fb7 to c1e5c6f Compare June 22, 2026 13:24
@rsempe
rsempe force-pushed the products-and-plans-api branch 2 times, most recently from b56be52 to 2d19901 Compare June 22, 2026 15:06
@rsempe
rsempe force-pushed the products-and-plans-rate-cards branch 4 times, most recently from e2fde88 to c0ab090 Compare June 22, 2026 15:28
@rsempe
rsempe force-pushed the products-and-plans-api branch 2 times, most recently from 51b842a to 8393467 Compare June 22, 2026 19:21
@rsempe
rsempe force-pushed the products-and-plans-rate-cards branch from c0ab090 to ec9724a Compare June 22, 2026 19:21
@rsempe
rsempe force-pushed the products-and-plans-api branch from 8393467 to 4eee616 Compare June 22, 2026 20:53
Comment thread app/serializers/v1/rate_card_serializer.rb
Comment thread app/graphql/types/rate_cards/object.rb Outdated
Comment thread app/graphql/types/rate_cards/object.rb
rsempe added 7 commits August 12, 2026 14:50
GraphQL surface for rate cards and their rates, powering the rate cards tabs of
the catalog and the rate timeline management.

Add the RateCard and RateCardRate object types with their enums (status exposed
as a derived value), create/update inputs, Create/Update/Destroy mutations for
both entities backed by the services, and single + collection rate card
resolvers with pagination, search and product scoping. Rate cards are
exposed on the Product type and join the activity log resource union; a
rate_cards permission family is registered. Regenerate the GraphQL schema dumps.
The rate cards list needs the active rate and the rate count per card, but
the rate card type exposed the whole rates collection inline, which is a
payload and N+1 liability and duplicates a dedicated rates query.

Drop the nested rates field from the RateCard GraphQL type; add active_rate
and rates_count instead, and expose the rates of a card through a new
rateCardRates resolver / RateCardRatesQuery. The REST serializer gains
rates_count and an on-demand active_rate. Add server-side rate card filters
by code, product_code and product_filter_code. Creation still
accepts a nested rates array (GraphQL input + service) so a card can be
authored with its pricing in one call; later appends go through the
dedicated rates endpoint.
regroup_paid_fees became a NOT NULL enum with none as its default. The
services and validation on this branch still read null as the absence of
regrouping, so every card carrying the new default would have failed the
compatibility validation, and an explicit null in an update read as a
locked-field change.

Read none, not null, as the no-regrouping state in the compatibility
validation. Creation falls back to the column default when the caller omits
the value or sends null, and an update normalises an explicit null to none
before the locked-field comparison, so resetting the field on a card with
rates is not a phantom price change. The GraphQL field is now non-nullable.
## Context

The rate column was renamed to effective_from on the data model, and arrears
rates now require date granularity.

## Description

Rename the remaining effective_datetime references on the rate card layer:
services, query, serializer, GraphQL types and the schema dumps. Spec rate
values normalise to midnight so they satisfy the arrears date rule; ordering
between rates is unchanged.
## Context

The strict arrears contract — refusing datetime strings at the REST
boundary with must_be_a_date — was replaced by canonicalization: any
date or datetime is accepted and an arrears value is normalized to its
day's midnight by the model, keeping one rate per day through the
unique index.

## Description

Cover the lenient contract at the service level: a datetime on an
arrears card is stored at midnight, a bare date is accepted, a second
rate on the same day fails with value_already_exist whatever its time,
and advance cards keep full instants while converting bare dates to
midnight.
## Context

Card lists ran per-row queries for rates_count and the attachment lock
signal, the same shape the catalog types already batch through
dataloader sources.

## Description

Resolve rates_count through CountByForeignKey and the attachment flag
through AttachedToPlanOrSubscription, which gains a join-less rate_card
grouping. The serializer reads rates through size so the REST index can
preload them.
## Context

Review findings on the card GraphQL surface: active_rate and
attached_to_subscriptions still ran per-row queries on lists, and the
activity-log payloads silently lost their rates when the API payloads
stopped nesting them.

## Description

Batch active_rate through a DISTINCT ON source and the subscription
attachment flag through its own source, and restore the opt-in rates
include on the serializer so activity payloads carry the full timeline
like plans carry their charges.
Comment thread app/graphql/sources/attached_to_subscriptions.rb

@tiagolupepic tiagolupepic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a small comment and it's not a blocker

:shipit:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants