Skip to content

Commit c0227cc

Browse files
committed
feat(products): add rate card GraphQL mutations and resolvers
## Context GraphQL surface for rate cards and their rates, powering the rate cards tabs of the catalog and the rate timeline management. ## Description 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 item scoping. Rate cards are exposed on the ProductItem type and join the activity log resource union; a rate_cards permission family is registered. Regenerate the GraphQL schema dumps.
1 parent 397a379 commit c0227cc

39 files changed

Lines changed: 3679 additions & 458 deletions
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# frozen_string_literal: true
2+
3+
module Mutations
4+
module RateCardRates
5+
class Create < BaseMutation
6+
include AuthenticableApiUser
7+
include RequiredOrganization
8+
9+
REQUIRED_PERMISSION = "rate_cards:create"
10+
11+
graphql_name "CreateRateCardRate"
12+
description "Adds a rate to a rate card"
13+
14+
input_object_class Types::RateCardRates::CreateInput
15+
type Types::RateCardRates::Object
16+
17+
def resolve(**args)
18+
rate_card = current_organization.rate_cards.find_by(id: args[:rate_card_id])
19+
result = ::RateCardRates::CreateService.call(rate_card:, params: args.except(:rate_card_id))
20+
21+
result.success? ? result.rate_card_rate : result_error(result)
22+
end
23+
end
24+
end
25+
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# frozen_string_literal: true
2+
3+
module Mutations
4+
module RateCardRates
5+
class Destroy < BaseMutation
6+
include AuthenticableApiUser
7+
include RequiredOrganization
8+
9+
REQUIRED_PERMISSION = "rate_cards:delete"
10+
11+
graphql_name "DestroyRateCardRate"
12+
description "Deletes a pending rate of a rate card"
13+
14+
argument :id, ID, required: true
15+
16+
field :id, ID, null: true
17+
18+
def resolve(id:)
19+
rate_card_rate = current_organization.rate_card_rates.find_by(id:)
20+
result = ::RateCardRates::DestroyService.call(rate_card_rate:)
21+
22+
result.success? ? result.rate_card_rate : result_error(result)
23+
end
24+
end
25+
end
26+
end
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# frozen_string_literal: true
2+
3+
module Mutations
4+
module RateCardRates
5+
class Update < BaseMutation
6+
include AuthenticableApiUser
7+
include RequiredOrganization
8+
9+
REQUIRED_PERMISSION = "rate_cards:update"
10+
11+
graphql_name "UpdateRateCardRate"
12+
description "Updates a rate of a rate card"
13+
14+
input_object_class Types::RateCardRates::UpdateInput
15+
type Types::RateCardRates::Object
16+
17+
def resolve(**args)
18+
rate_card_rate = current_organization.rate_card_rates.find_by(id: args[:id])
19+
result = ::RateCardRates::UpdateService.call(rate_card_rate:, params: args.except(:id))
20+
21+
result.success? ? result.rate_card_rate : result_error(result)
22+
end
23+
end
24+
end
25+
end
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# frozen_string_literal: true
2+
3+
module Mutations
4+
module RateCards
5+
class Create < BaseMutation
6+
include AuthenticableApiUser
7+
include RequiredOrganization
8+
9+
REQUIRED_PERMISSION = "rate_cards:create"
10+
11+
graphql_name "CreateRateCard"
12+
description "Creates a new rate card"
13+
14+
input_object_class Types::RateCards::CreateInput
15+
type Types::RateCards::Object
16+
17+
def resolve(**args)
18+
product_item = current_organization.product_items.find_by(id: args[:product_item_id])
19+
20+
params = args.except(:product_item_id)
21+
params[:rates] = params[:rates].map(&:to_h) if params[:rates]
22+
23+
result = ::RateCards::CreateService.call(product_item:, params:)
24+
25+
result.success? ? result.rate_card : result_error(result)
26+
end
27+
end
28+
end
29+
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# frozen_string_literal: true
2+
3+
module Mutations
4+
module RateCards
5+
class Destroy < BaseMutation
6+
include AuthenticableApiUser
7+
include RequiredOrganization
8+
9+
REQUIRED_PERMISSION = "rate_cards:delete"
10+
11+
graphql_name "DestroyRateCard"
12+
description "Deletes a rate card"
13+
14+
argument :id, ID, required: true
15+
16+
field :id, ID, null: true
17+
18+
def resolve(id:)
19+
rate_card = current_organization.rate_cards.find_by(id:)
20+
result = ::RateCards::DestroyService.call(rate_card:)
21+
22+
result.success? ? result.rate_card : result_error(result)
23+
end
24+
end
25+
end
26+
end
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# frozen_string_literal: true
2+
3+
module Mutations
4+
module RateCards
5+
class Update < BaseMutation
6+
include AuthenticableApiUser
7+
include RequiredOrganization
8+
9+
REQUIRED_PERMISSION = "rate_cards:update"
10+
11+
graphql_name "UpdateRateCard"
12+
description "Updates an existing rate card"
13+
14+
input_object_class Types::RateCards::UpdateInput
15+
type Types::RateCards::Object
16+
17+
def resolve(**args)
18+
rate_card = current_organization.rate_cards.find_by(id: args[:id])
19+
result = ::RateCards::UpdateService.call(rate_card:, params: args.except(:id))
20+
21+
result.success? ? result.rate_card : result_error(result)
22+
end
23+
end
24+
end
25+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
module Resolvers
4+
class RateCardResolver < Resolvers::BaseResolver
5+
include AuthenticableApiUser
6+
include RequiredOrganization
7+
8+
REQUIRED_PERMISSION = "rate_cards:view"
9+
10+
description "Query a single rate card of an organization"
11+
12+
argument :id, ID, required: true, description: "Uniq ID of the rate card"
13+
14+
type Types::RateCards::Object, null: true
15+
16+
def resolve(id: nil)
17+
current_organization.rate_cards.find(id)
18+
rescue ActiveRecord::RecordNotFound
19+
not_found_error(resource: "rate_card")
20+
end
21+
end
22+
end
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# frozen_string_literal: true
2+
3+
module Resolvers
4+
class RateCardsResolver < Resolvers::BaseResolver
5+
include AuthenticableApiUser
6+
include RequiredOrganization
7+
8+
REQUIRED_PERMISSION = "rate_cards:view"
9+
10+
description "Query rate cards of an organization"
11+
12+
argument :limit, Integer, required: false
13+
argument :page, Integer, required: false
14+
argument :product_item_id, ID, required: false
15+
argument :search_term, String, required: false
16+
17+
type Types::RateCards::Object.collection_type, null: false
18+
19+
def resolve(page: nil, limit: nil, search_term: nil, product_item_id: nil)
20+
result = ::RateCardsQuery.call(
21+
organization: current_organization,
22+
search_term:,
23+
pagination: {page:, limit:},
24+
filters: {product_item_id:}
25+
)
26+
27+
result.rate_cards
28+
end
29+
end
30+
end

app/graphql/types/activity_logs/resource_object.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ class ResourceObject < Types::BaseUnion
2121
Types::Entitlement::FeatureObject,
2222
Types::Products::Object,
2323
Types::ProductItems::Object,
24-
Types::ProductItemFilters::Object
24+
Types::ProductItemFilters::Object,
25+
Types::RateCards::Object
2526

2627
def self.resolve_type(object, _context)
2728
case object.class.to_s
@@ -55,6 +56,8 @@ def self.resolve_type(object, _context)
5556
Types::ProductItems::Object
5657
when "ProductItemFilter"
5758
Types::ProductItemFilters::Object
59+
when "RateCard"
60+
Types::RateCards::Object
5861
else
5962
raise "Unexpected activity log resource type: #{object.inspect}"
6063
end

app/graphql/types/mutation_type.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,14 @@ class MutationType < Types::BaseObject
243243
field :destroy_product_item_filter, mutation: Mutations::ProductItemFilters::Destroy
244244
field :update_product_item_filter, mutation: Mutations::ProductItemFilters::Update
245245

246+
field :create_rate_card, mutation: Mutations::RateCards::Create
247+
field :destroy_rate_card, mutation: Mutations::RateCards::Destroy
248+
field :update_rate_card, mutation: Mutations::RateCards::Update
249+
250+
field :create_rate_card_rate, mutation: Mutations::RateCardRates::Create
251+
field :destroy_rate_card_rate, mutation: Mutations::RateCardRates::Destroy
252+
field :update_rate_card_rate, mutation: Mutations::RateCardRates::Update
253+
246254
field :create_role, mutation: Mutations::Roles::Create
247255
field :destroy_role, mutation: Mutations::Roles::Destroy
248256
field :update_role, mutation: Mutations::Roles::Update

0 commit comments

Comments
 (0)