Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions app/controllers/concerns/wallet_actions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,13 @@ def wallet_index(external_customer_id:, currency:, billing_entity_codes: nil)
:billing_entity,
:metadata,
:billable_metrics,
{customer: :billing_entity},
:billing_object_connections,
{customer: [:billing_entity, :payment_provider_customers, :integration_customers]},
{applied_invoice_custom_sections: :invoice_custom_section},
{recurring_transaction_rules: {applied_invoice_custom_sections: :invoice_custom_section}}
{recurring_transaction_rules: [
:billing_object_connections,
{applied_invoice_custom_sections: :invoice_custom_section}
]}
),
::V1::WalletSerializer,
collection_name: "wallets",
Expand Down
13 changes: 13 additions & 0 deletions app/graphql/types/connections/category_enum.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

module Types
module Connections
class CategoryEnum < Types::BaseEnum
graphql_name "ConnectionCategoryEnum"

BillingObjectConnection::CATEGORIES.each_key do |category|
value category
end
end
end
end
15 changes: 15 additions & 0 deletions app/graphql/types/connections/object.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module Types
module Connections
class Object < Types::BaseObject
graphql_name "ConnectionRouting"
description "The connection a billing object routes to for one category, and where that choice came from"

field :behavior, Types::Connections::ResolvedBehaviorEnum, null: false
field :category, Types::Connections::CategoryEnum, null: false
field :code, String, null: true,
description: "Code of the connection in effect. Null when the category is skipped or nothing resolves"
end
end
end
14 changes: 14 additions & 0 deletions app/graphql/types/connections/resolved_behavior_enum.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

module Types
module Connections
class ResolvedBehaviorEnum < Types::BaseEnum
graphql_name "ConnectionResolvedBehaviorEnum"
description "How a billing object routes a category: its own choice, or inherited from the customer"

ConnectionResolvable::ROUTING_BEHAVIORS.each do |behavior|
value behavior
end
end
end
end
1 change: 1 addition & 0 deletions app/graphql/types/wallets/object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Object < Types::BaseObject
field :last_ongoing_balance_sync_at, GraphQL::Types::ISO8601DateTime, null: true

field :activity_logs, [Types::ActivityLogs::Object], null: true
field :connections, [Types::Connections::Object], null: false, method: :connection_routing
field :recurring_transaction_rules, [Types::Wallets::RecurringTransactionRules::Object], null: true

field :invoice_requires_successful_payment, Boolean, null: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class Object < Types::BaseObject

field :lago_id, ID, null: false, method: :id

field :connections, [Types::Connections::Object], null: false, method: :connection_routing

field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :expiration_at, GraphQL::Types::ISO8601DateTime, null: true
field :granted_credits, String, null: false
Expand Down
33 changes: 33 additions & 0 deletions app/models/concerns/connection_resolvable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ module ConnectionResolvable

CATEGORIES = BillingObjectConnection::CATEGORIES

# Read-side only: the absence of an override row is reported as "inherit". The column itself
# only ever holds "specific" or "skip".
INHERIT_BEHAVIOR = "inherit"
ROUTING_BEHAVIORS = (BillingObjectConnection::BEHAVIORS.values + [INHERIT_BEHAVIOR]).freeze

Routing = Data.define(:category, :behavior, :code)

def effective_payment_connection
effective_connection(CATEGORIES[:payment])
end
Expand All @@ -30,6 +37,32 @@ def effective_crm_connection
effective_connection(CATEGORIES[:crm])
end

# The routing of every category, for read surfaces: the stored behaviour ("inherit" when no
# override row exists) alongside the code of the connection actually in effect. Overrides are
# loaded once rather than per category, so `includes(:billing_object_connections)` on a
# collection keeps this to one query.
def connection_routing
overrides = billing_object_connections.index_by(&:category)

CATEGORIES.each_value.map do |category|
override = overrides[category]

connection = if override.nil?
customer_default_connection(category)
elsif override.skip?
nil
else
override_connection(override, category)
end

Routing.new(
category: category,
behavior: override&.behavior || INHERIT_BEHAVIOR,
code: connection&.code
)
end
end

private

def effective_connection(category)
Expand Down
12 changes: 12 additions & 0 deletions app/serializers/v1/wallet_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def serialize
payload.merge!(limitations) if include?(:limitations)
payload.merge!(applied_invoice_custom_sections) if include?(:applied_invoice_custom_sections)
payload.merge!(payment_method)
payload.merge!(connections)
payload.merge!(metadata) if model.metadata.present?

payload
Expand Down Expand Up @@ -73,6 +74,17 @@ def payment_method
}
end

# Keyed by category, mirroring the shape accepted on create/update. Every category is present,
# with the behaviour ("inherit" when the wallet makes no choice of its own) and the code of the
# connection actually in effect.
def connections
{
connections: model.connection_routing.index_by { it.category }.transform_values do |routing|
{behavior: routing.behavior, code: routing.code}
end
}
end

def applied_invoice_custom_sections
::CollectionSerializer.new(
model.applied_invoice_custom_sections,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def serialize

payload.merge!(applied_invoice_custom_sections)
payload.merge!(payment_method)
payload.merge!(connections)

payload
end
Expand All @@ -49,6 +50,15 @@ def payment_method
}
}
end

# Keyed by category, mirroring the shape accepted on create/update.
def connections
{
connections: model.connection_routing.index_by { it.category }.transform_values do |routing|
{behavior: routing.behavior, code: routing.code}
end
}
end
end
end
end
31 changes: 31 additions & 0 deletions schema.graphql

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading