diff --git a/app/graphql/mutations/create_stake_remove_order.rb b/app/graphql/mutations/create_stake_remove_order.rb new file mode 100644 index 0000000..0669e2f --- /dev/null +++ b/app/graphql/mutations/create_stake_remove_order.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +module Mutations + class CreateStakeRemoveOrder < BaseMutation + field :order, Types::StakeOrderType, null: true + + argument :order, Inputs::CreateStakeOrderAttributesInput, required: true + + def resolve(order:) + currency_id = decode_id(order[:currency_id]) + amount = BigDecimal(order[:amount]) + + ActiveRecord::Base.transaction do + record = StakeOrder.find_or_initialize_by( + pool_name: order[:pool_name], + user_id: current_user.id, + currency_id: currency_id, + status: :processing + ) + + record.amount += amount + record.save! + + { order: record } + rescue ActiveRecord::RecordInvalid => e + { errors: Resolvers::ModelErrors.from_active_record_model(e.record) } + end + end + end +end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 8ecc552..c4eee07 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true module Types class MutationType < Types::BaseObject + field :create_stake_remove_order, mutation: Mutations::CreateStakeRemoveOrder field :create_stake_order, mutation: Mutations::CreateStakeOrder field :create_sell_crypto_order, mutation: Mutations::CreateSellCryptoOrder field :create_buy_crypto_order, mutation: Mutations::CreateBuyCryptoOrder diff --git a/app/javascript/__generated__/schema.graphql b/app/javascript/__generated__/schema.graphql index c046336..1358bfd 100644 --- a/app/javascript/__generated__/schema.graphql +++ b/app/javascript/__generated__/schema.graphql @@ -180,6 +180,33 @@ type CreateStakeOrderPayload { order: StakeOrder } +""" +Autogenerated input type of CreateStakeRemoveOrder +""" +input CreateStakeRemoveOrderInput { + """ + A unique identifier for the client performing the mutation. + """ + clientMutationId: String + order: CreateStakeOrderAttributesInput! +} + +""" +Autogenerated return type of CreateStakeRemoveOrder +""" +type CreateStakeRemoveOrderPayload { + """ + A unique identifier for the client performing the mutation. + """ + clientMutationId: String + + """ + Errors encountered during execution of the mutation. + """ + errors: [RecordInvalid!] + order: StakeOrder +} + type Currency implements Node { id: ID! name: String! @@ -245,6 +272,12 @@ type Mutation { """ input: CreateStakeOrderInput! ): CreateStakeOrderPayload + createStakeRemoveOrder( + """ + Parameters for CreateStakeRemoveOrder + """ + input: CreateStakeRemoveOrderInput! + ): CreateStakeRemoveOrderPayload } """ diff --git a/spec/graphql/mutations/create_stake_remove_order_spec.rb b/spec/graphql/mutations/create_stake_remove_order_spec.rb new file mode 100644 index 0000000..ee0aa9a --- /dev/null +++ b/spec/graphql/mutations/create_stake_remove_order_spec.rb @@ -0,0 +1,120 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe(Mutations::CreateStakeRemoveOrder, type: :mutation) do + let(:query_string) do + <<~GQL + mutation( + $currencyId: ID!, + $amount: String!, + $poolName: String!, + ) { + createStakeRemoveOrder(input: { + order: { + currencyId: $currencyId, + amount: $amount, + poolName: $poolName, + } + }) { + errors { + fullMessages + fieldName + messages + path + } + order { + poolName + status + amount + } + } + } + GQL + end + + context "when the user has enough balance" do + it "withdraws from his account and creates a buy order" do + currency = create(:currency) + user = create( + :user, + balances: [ + build(:balance, currency: currency, amount: 0), + ] + ) + + currency_global_id = GraphQL::Schema::UniqueWithinType.encode("Currency", currency.id) + + variables = { + "currencyId": currency_global_id, + "amount": "-200.80", + "poolName": "CAKE/BNB", + "status": "PROCESSING", + } + + context = { current_user: user } + + result = XStakeSchema.execute( + query_string, + variables: variables, + context: context + ).to_h.with_indifferent_access + + expect(result).to(eq({ + "data" => { + "createStakeRemoveOrder" => { + "errors" => nil, + "order" => { + "status" => "PROCESSING", + "amount" => "-200.8", + "poolName" => "CAKE/BNB", + }, + }, + }, + })) + end + end + + context "when it repeats the mutation with a request in `processing`" do + it "update amount from the order" do + currency = create(:currency) + user = create( + :user, + balances: [ + build(:balance, currency: currency, amount: 0), + ] + ) + + currency_global_id = GraphQL::Schema::UniqueWithinType.encode("Currency", currency.id) + + create(:stake_order, amount: -200.8, user: user, pool_name: "CAKE/BNB", currency: currency) + + variables = { + "currencyId": currency_global_id, + "amount": "-200.80", + "poolName": "CAKE/BNB", + } + + context = { current_user: user } + + result = XStakeSchema.execute( + query_string, + variables: variables, + context: context + ).to_h.with_indifferent_access + + expect(result).to(eq({ + "data" => { + "createStakeRemoveOrder" => { + "errors" => nil, + "order" => { + "status" => "PROCESSING", + "amount" => "-401.6", + "poolName" => "CAKE/BNB", + }, + }, + }, + })) + end + end +end