Skip to content

Commit

Permalink
feat(manual-payments): Add payment resolver, and filter by customer e…
Browse files Browse the repository at this point in the history
…xternal_id
  • Loading branch information
ivannovosad committed Jan 24, 2025
1 parent 00781e2 commit 385f811
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 20 deletions.
22 changes: 22 additions & 0 deletions app/graphql/resolvers/payment_resolver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

module Resolvers
class PaymentResolver < Resolvers::BaseResolver
include AuthenticableApiUser
include RequiredOrganization

REQUIRED_PERMISSION = 'payments:view'

description 'Query a single Payment'

argument :id, ID, required: true, description: 'Uniq ID of the payment'

type Types::Payments::Object, null: true

def resolve(id:)
Payment.for_organization(current_organization).find(id)
rescue ActiveRecord::RecordNotFound
not_found_error(resource: 'payment')
end
end
end
6 changes: 4 additions & 2 deletions app/graphql/resolvers/payments_resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@ class PaymentsResolver < Resolvers::BaseResolver

description "Query payments of an organization"

argument :external_customer_id, ID, required: false
argument :invoice_id, ID, required: false
argument :limit, Integer, required: false
argument :page, Integer, required: false

type Types::Payments::Object.collection_type, null: false

def resolve(page: nil, limit: nil, invoice_id: nil)
def resolve(page: nil, limit: nil, invoice_id: nil, external_customer_id: nil)
result = PaymentsQuery.call(
organization: current_organization,
filters: {
invoice_id:
invoice_id:,
external_customer_id:
},
pagination: {
page:,
Expand Down
1 change: 1 addition & 0 deletions app/graphql/types/query_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class QueryType < Types::BaseObject
field :organization, resolver: Resolvers::OrganizationResolver
field :overdue_balances, resolver: Resolvers::Analytics::OverdueBalancesResolver
field :password_reset, resolver: Resolvers::PasswordResetResolver
field :payment, resolver: Resolvers::PaymentResolver
field :payment_provider, resolver: Resolvers::PaymentProviderResolver
field :payment_providers, resolver: Resolvers::PaymentProvidersResolver
field :payment_requests, resolver: Resolvers::PaymentRequestsResolver
Expand Down
12 changes: 11 additions & 1 deletion schema.graphql

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

41 changes: 41 additions & 0 deletions schema.json

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

61 changes: 61 additions & 0 deletions spec/graphql/resolvers/payment_resolver_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe Resolvers::PaymentResolver, type: :graphql do
let(:required_permission) { 'payments:view' }

let(:query) do
<<~GQL
query($id: ID!) {
payment(id: $id) {
id
}
}
GQL
end

let(:membership) { create(:membership) }
let(:organization) { membership.organization }
let(:customer) { create(:customer, organization:) }
let(:invoice) { create(:invoice, customer:, organization:, fees_amount_cents: 10) }
let(:payment) { create(:payment, payable: invoice) }

before { payment }

it_behaves_like 'requires current user'
it_behaves_like 'requires current organization'
it_behaves_like 'requires permission', 'payments:view'

it 'returns a single payment' do
result = execute_graphql(
current_user: membership.user,
current_organization: organization,
permissions: required_permission,
query:,
variables: {
id: payment.id
}
)

data = result['data']['payment']

expect(data['id']).to eq(payment.id)
end

context 'when payment is not found' do
it 'returns an error' do
result = execute_graphql(
current_user: membership.user,
current_organization: invoice.organization,
permissions: required_permission,
query:,
variables: {
id: 'foo'
}
)

expect_graphql_error(result:, message: 'Resource not found')
end
end
end
96 changes: 79 additions & 17 deletions spec/graphql/resolvers/payments_resolver_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,86 @@
it_behaves_like "requires current organization"
it_behaves_like "requires permission", "payments:view"

it "returns a list of payments", :aggregate_failures do
result = execute_graphql(
current_user: membership.user,
current_organization: organization,
permissions: required_permission,
query:,
variables: {
invoiceId: invoice1.id
}
)
context "when invoice id is present" do
let(:query) do
<<~GQL
query($invoiceId: ID!) {
payments(invoiceId: $invoiceId, limit: 5) {
collection {
id
amountCents
customer { id }
paymentProviderType
payable {
... on Invoice { id }
... on PaymentRequest { id }
}
}
metadata { currentPage, totalCount }
}
}
GQL
end

it "returns a list of payments", :aggregate_failures do
result = execute_graphql(
current_user: membership.user,
current_organization: organization,
permissions: required_permission,
query:,
variables: {
invoiceId: invoice1.id
}
)

payments_response = result["data"]["payments"]

expect(payments_response["collection"].count).to eq(1)
expect(payments_response["collection"].first["id"]).to eq(payment.id)
expect(payments_response["collection"].first["amountCents"]).to eq(payment.amount_cents.to_s)
expect(payments_response["collection"].first["paymentProviderType"]).to eq("stripe")
expect(payments_response["collection"].first["payable"]["id"]).to eq(invoice1.id)
expect(payments_response["collection"].first["customer"]["id"]).to eq(customer.id)
end
end

context "when external customer id is present" do
let(:query) do
<<~GQL
query($externalCustomerId: ID!) {
payments(externalCustomerId: $externalCustomerId, limit: 5) {
collection {
id
amountCents
customer { id }
paymentProviderType
payable {
... on Invoice { id }
... on PaymentRequest { id }
}
}
metadata { currentPage, totalCount }
}
}
GQL
end

it "returns a list of payments", :aggregate_failures do
result = execute_graphql(
current_user: membership.user,
current_organization: organization,
permissions: required_permission,
query:,
variables: {
externalCustomerId: customer.external_id
}
)

payments_response = result["data"]["payments"]
payments_response = result["data"]["payments"]

expect(payments_response["collection"].count).to eq(1)
expect(payments_response["collection"].first["id"]).to eq(payment.id)
expect(payments_response["collection"].first["amountCents"]).to eq(payment.amount_cents.to_s)
expect(payments_response["collection"].first["paymentProviderType"]).to eq("stripe")
expect(payments_response["collection"].first["payable"]["id"]).to eq(invoice1.id)
expect(payments_response["collection"].first["customer"]["id"]).to eq(customer.id)
expect(payments_response["collection"].count).to eq(2)
expect(payments_response["collection"].map { |payable| payable.dig("payable", "id") })
.to contain_exactly(invoice1.id, invoice2.id)
end
end
end

0 comments on commit 385f811

Please sign in to comment.