From bd97df8fb9a50c71faed6e1a7c04088234639ae1 Mon Sep 17 00:00:00 2001 From: dhodov_sftsrv Date: Tue, 27 Aug 2024 12:07:12 +0300 Subject: [PATCH] add advanced invoive --- CHANGELOG.md | 7 ++ Gemfile | 2 + Gemfile.lock | 22 +++++- README.md | 23 +++++++ lib/monopay-ruby/invoices/advanced_invoice.rb | 69 +++++++++++++++++++ lib/monopay-ruby/invoices/simple_invoice.rb | 19 +++-- lib/monopay-ruby/version.rb | 2 +- spec/lib/invoices/advanced_invoice_spec.rb | 53 ++++++++++++++ spec/lib/invoices/simple_invoice_spec.rb | 8 ++- 9 files changed, 196 insertions(+), 9 deletions(-) create mode 100644 lib/monopay-ruby/invoices/advanced_invoice.rb create mode 100644 spec/lib/invoices/advanced_invoice_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index bfa6a99..65b16b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.1.0] - 2024-08-12 +- add ability make payments' requests more advanced by adding more params into `MonopayRuby::Invoices::AdvancedInvoice::create` method +- change private methods to protected +- modify `request_body` for additional params +- add protected method `default_params` +- add more details about `MonopayRuby::Invoices::AdvancedInvoice` into `README.md` + ## [1.0.0] - 2023-06-27 ### Changed diff --git a/Gemfile b/Gemfile index d7d28ad..1f1e89f 100644 --- a/Gemfile +++ b/Gemfile @@ -6,3 +6,5 @@ source "https://rubygems.org" gemspec gem "rake", "~> 13.0" +gem 'activesupport', '~> 7.0' +gem 'yard' diff --git a/Gemfile.lock b/Gemfile.lock index 863fd18..b646081 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - monopay-ruby (1.0.0) + monopay-ruby (1.1.0) base64 (~> 0.1.1) json (~> 2.5) money (~> 6.13) @@ -10,13 +10,26 @@ PATH GEM remote: https://rubygems.org/ specs: + activesupport (7.1.3.4) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + minitest (>= 5.1) + mutex_m + tzinfo (~> 2.0) base64 (0.1.1) + bigdecimal (3.1.8) coderay (1.1.3) concurrent-ruby (1.2.2) + connection_pool (2.4.1) diff-lcs (1.5.0) docile (1.4.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) + drb (2.2.1) http-accept (1.7.0) http-cookie (1.0.5) domain_name (~> 0.5) @@ -27,8 +40,10 @@ GEM mime-types (3.4.1) mime-types-data (~> 3.2015) mime-types-data (3.2023.0218.1) + minitest (5.25.1) money (6.16.0) i18n (>= 0.6.4, <= 2) + mutex_m (0.2.0) netrc (0.11.0) pry (0.14.2) coderay (~> 1.1) @@ -58,20 +73,25 @@ GEM simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) unf (0.1.4) unf_ext unf_ext (0.0.8.2) + yard (0.9.36) PLATFORMS arm64-darwin-21 x86_64-linux DEPENDENCIES + activesupport (~> 7.0) monopay-ruby! pry (~> 0.14.2) rake (~> 13.0) rspec (~> 3.0) simplecov (~> 0.22.0) + yard BUNDLED WITH 2.4.13 diff --git a/README.md b/README.md index 61117a1..5a21272 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,29 @@ class PaymentsController < ApplicationController end ``` +## Generate advanced payment request: + +```ruby +# app/controllers/payments_controller.rb +class PaymentsController < ApplicationController + def create + payment = MonopayRuby::Invoices::AdvancedInvoice.new( + redirect_url: "https://example.com", + webhook_url: "https://example.com/payments/webhook" + ) + + if payment.create(amount, additional_params: {}) + # your success code processing + else + # your error code processing + # flash[:error] = payment.error_messages + end + end +end +``` + +`additional_params` - [Read more about params](https://api.monobank.ua/docs/acquiring.html) + ### Verify transaction ```ruby diff --git a/lib/monopay-ruby/invoices/advanced_invoice.rb b/lib/monopay-ruby/invoices/advanced_invoice.rb new file mode 100644 index 0000000..0c02bbd --- /dev/null +++ b/lib/monopay-ruby/invoices/advanced_invoice.rb @@ -0,0 +1,69 @@ +require_relative 'simple_invoice' + +module MonopayRuby + module Invoices + class AdvancedInvoice < MonopayRuby::Invoices::SimpleInvoice + attr_reader :additional_params, :amount + + # Create invoice + # + # This method sets up the required instance variables and then calls the `create` + # method from the parent class with the relevant parameters. + # + # @param amount [Numeric] The amount of the payment. + # @param additional_params [Hash] (optional) Additional parameters for the payment. + # - :merchantPaymInfo [Hash] Information about the merchant payment. + # - :destination [String] The destination of the payment. + # - :reference [String] A reference for the payment. + # + # @return [Object] The result of the `create` method in the parent class, + # which returns true if invoice was created successfully, false otherwise + # + # @example Create a payment with amount and additional parameters + # create(100, additional_params: { merchantPaymInfo: { destination: "Happy payment", reference: "ref123" } }) + + def create(amount, additional_params: {}) + @amount = amount + @additional_params = additional_params + @destination = @additional_params&.dig(:merchantPaymInfo, :destination) + @reference = @additional_params&.dig(:merchantPaymInfo, :reference) + + super(amount, destination: @destination, reference: @reference) + end + + protected + + def request_body + current_params = default_params + + return current_params.to_json if additional_params.blank? + + unless additional_params[:merchantPaymInfo].blank? + current_params[:merchantPaymInfo] = { + reference: @reference, + destination: @destination + }.merge!(additional_params[:merchantPaymInfo].except(:reference, :destination)) + end + + current_params.merge!(additional_params.except(:merchantPaymInfo)) + + # TODO: add sum and qty params into present additional params + set_sum_and_qty_params(current_params&.dig(:merchantPaymInfo, :basketOrder)) + set_sum_and_qty_params(current_params[:items]) + + current_params.to_json + end + + def set_sum_and_qty_params(current_param) + return if current_param.blank? + + current_param.each do |item| + return if item.blank? + + item[:sum] = convert_to_cents(item[:sum] || amount) + item[:qty] = item[:qty] || 1 + end + end + end + end +end diff --git a/lib/monopay-ruby/invoices/simple_invoice.rb b/lib/monopay-ruby/invoices/simple_invoice.rb index 9d6cf8a..e7523d6 100644 --- a/lib/monopay-ruby/invoices/simple_invoice.rb +++ b/lib/monopay-ruby/invoices/simple_invoice.rb @@ -1,3 +1,4 @@ +require 'active_support/all' require "bigdecimal" require "money" @@ -53,12 +54,11 @@ def create(amount, destination: nil, reference: nil) end end - private + protected - # Request body required for Monobank API - # - # @return [Hash] request body - def request_body + # Default params required for request into Monobank + + def default_params # TODO: add "ccy" and another missing params # TODO: remove nil valued params { @@ -69,7 +69,14 @@ def request_body reference: reference, destination: destination } - }.to_json + } + end + + # Request body required for Monobank API + # + # @return [Hash] request body + def request_body + default_params.to_json end def convert_to_cents(amount) diff --git a/lib/monopay-ruby/version.rb b/lib/monopay-ruby/version.rb index e55885d..68dab9d 100644 --- a/lib/monopay-ruby/version.rb +++ b/lib/monopay-ruby/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module MonopayRuby - VERSION = "1.0.0" + VERSION = "1.1.0" end diff --git a/spec/lib/invoices/advanced_invoice_spec.rb b/spec/lib/invoices/advanced_invoice_spec.rb new file mode 100644 index 0000000..256721a --- /dev/null +++ b/spec/lib/invoices/advanced_invoice_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +RSpec.describe MonopayRuby::Invoices::AdvancedInvoice do + describe "#new" do + let!(:redirect_url) { "https://redirect.example.com" } + let!(:webhook_url) { "https://webhook.example.com" } + + context "with keyword parameters" do + subject { described_class.new(redirect_url: redirect_url, webhook_url: webhook_url) } + + it "initializes with correct redirect_url" do + expect(subject.redirect_url).to eq(redirect_url) + end + + it "initializes with correct webhook_url" do + expect(subject.webhook_url).to eq(webhook_url) + end + end + + context "without keyword parameters" do + subject { described_class.new(redirect_url, webhook_url) } + + it "raises an ArgumentError" do + expect { subject }.to raise_error(ArgumentError) + end + end + + context "without parameters" do + subject { described_class.new } + + it { is_expected.to be_a(described_class) } + end + end + + describe "#create" do + context "when request is successful" do + let(:simple_invoice_instance) { described_class.new } + let(:invoice_id) { "p2_9ZgpZVsl3" } + let(:page_url) { "https://pay.mbnk.biz/p2_9ZgpZVsl3" } + let(:basket_order) { { name: "product", qty: 1 } } + let(:other_params) { { ccy: 9 } } + let(:response_example) { { "invoiceId": invoice_id, "pageUrl": page_url } } + + before do + allow(RestClient).to receive(:post).and_return(double(body: response_example.to_json)) + end + + it "returns true" do + expect(simple_invoice_instance.create(2000, other_merchant_paymant_info_params: {basketOrder: [basket_order]}, other_params: other_params)).to be_truthy + end + end + end +end diff --git a/spec/lib/invoices/simple_invoice_spec.rb b/spec/lib/invoices/simple_invoice_spec.rb index 676c5e4..1157095 100644 --- a/spec/lib/invoices/simple_invoice_spec.rb +++ b/spec/lib/invoices/simple_invoice_spec.rb @@ -71,7 +71,13 @@ context "when request is failed" do context "with missing token" do # move this code to shared example or mb shared context - let(:missing_x_token_server_message) { { "errorDescription" => "Missing required header 'X-Token'" } } + let(:missing_x_token_server_message) { + { + "errCode" => "BAD_REQUEST", + "errText" => "Missing required header 'X-Token'", + "errorDescription" => "Missing required header 'X-Token'" + } + } let(:error_code) { "400 Bad Request" } let(:missing_x_token_header_error_message) do [error_code, missing_x_token_server_message].join(", ")