Skip to content

Commit

Permalink
add advanced invoive
Browse files Browse the repository at this point in the history
  • Loading branch information
dhodov committed Aug 28, 2024
1 parent 397d6ad commit d86027e
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 9 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## [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

## [1.0.0] - 2023-06-27

### Changed
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ source "https://rubygems.org"
gemspec

gem "rake", "~> 13.0"
gem 'activesupport', '~> 7.0'
20 changes: 19 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -58,6 +73,8 @@ 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)
Expand All @@ -67,6 +84,7 @@ PLATFORMS
x86_64-linux

DEPENDENCIES
activesupport (~> 7.0)
monopay-ruby!
pry (~> 0.14.2)
rake (~> 13.0)
Expand Down
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
73 changes: 73 additions & 0 deletions lib/monopay-ruby/invoices/advanced_invoice.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
require_relative 'simple_invoice'

module MonopayRuby
module Invoices
class AdvancedInvoice < MonopayRuby::Invoices::SimpleInvoice
attr_reader :additional_params, :amount

# Create invoice for Monobank API
#
# 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 [Boolean] 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 and modify sum and qty params of merchantPaymInfo[basketOrder] parameters if it is present
# TODO: add and modify sum and qty params of items parameters if it is present
set_sum_and_qty_params(current_params&.dig(:merchantPaymInfo, :basketOrder))
set_sum_and_qty_params(current_params[:items])

current_params.to_json
end

# Set sum and qty params
# @param current_param [Array] The current parameter to set sum and qty
# It sets the converted amount or sum parameter as sum and pasted quantity parameter or default value as qty parameters for the current parameter
# @return [Object] It could be Hash or Array or nil. It depends on the current parameter
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
19 changes: 13 additions & 6 deletions lib/monopay-ruby/invoices/simple_invoice.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'active_support/all'
require "bigdecimal"
require "money"

Expand Down Expand Up @@ -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
{
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/monopay-ruby/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module MonopayRuby
VERSION = "1.0.0"
VERSION = "1.1.0"
end
53 changes: 53 additions & 0 deletions spec/lib/invoices/advanced_invoice_spec.rb
Original file line number Diff line number Diff line change
@@ -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(:additional_params) { { merchantPaymInfo: { basketOrder: [basket_order] }, 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, additional_params: additional_params)).to be_truthy
end
end
end
end
8 changes: 7 additions & 1 deletion spec/lib/invoices/simple_invoice_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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(", ")
Expand Down

0 comments on commit d86027e

Please sign in to comment.