tamara 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop.yml +114 -0
- data/.rubocop_todo.yml +21 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +227 -0
- data/Guardfile +42 -0
- data/LICENSE.txt +21 -0
- data/README.md +290 -0
- data/Rakefile +19 -0
- data/lib/generators/tamara/install_generator.rb +15 -0
- data/lib/generators/tamara/templates/tamara.rb +8 -0
- data/lib/tamara/api/api_token.rb +14 -0
- data/lib/tamara/api/application_service.rb +48 -0
- data/lib/tamara/api/orders/authorize.rb +26 -0
- data/lib/tamara/api/orders/cancel.rb +38 -0
- data/lib/tamara/api/orders/create.rb +71 -0
- data/lib/tamara/api/orders/details/merchant_order.rb +28 -0
- data/lib/tamara/api/orders/details/tamara_order.rb +28 -0
- data/lib/tamara/api/orders.rb +56 -0
- data/lib/tamara/api/payment_options/check.rb +34 -0
- data/lib/tamara/api/payment_options.rb +13 -0
- data/lib/tamara/api/payment_types.rb +23 -0
- data/lib/tamara/api/payments/capture.rb +40 -0
- data/lib/tamara/api/payments.rb +16 -0
- data/lib/tamara/api/request.rb +49 -0
- data/lib/tamara/api/signature.rb +25 -0
- data/lib/tamara/api/webhooks.rb +28 -0
- data/lib/tamara/configuration.rb +5 -0
- data/lib/tamara/errors.rb +67 -0
- data/lib/tamara/hmac.rb +20 -0
- data/lib/tamara/json_schemas/address.rb +23 -0
- data/lib/tamara/json_schemas/amount.rb +19 -0
- data/lib/tamara/json_schemas/checkout_optional_keys.rb +11 -0
- data/lib/tamara/json_schemas/consumer.rb +21 -0
- data/lib/tamara/json_schemas/discount.rb +17 -0
- data/lib/tamara/json_schemas/item.rb +41 -0
- data/lib/tamara/json_schemas/merchant_url.rb +19 -0
- data/lib/tamara/json_schemas/orders/cancel.rb +30 -0
- data/lib/tamara/json_schemas/orders/create.rb +61 -0
- data/lib/tamara/json_schemas/payment_options/check.rb +25 -0
- data/lib/tamara/json_schemas/payment_types.rb +21 -0
- data/lib/tamara/json_schemas/payments/capture.rb +38 -0
- data/lib/tamara/json_schemas/risk_assessment.rb +65 -0
- data/lib/tamara/json_schemas/types/boolean.rb +15 -0
- data/lib/tamara/json_schemas/types/date.rb +17 -0
- data/lib/tamara/json_schemas/types/enum.rb +15 -0
- data/lib/tamara/json_schemas/types/float.rb +16 -0
- data/lib/tamara/json_schemas/types/integer.rb +17 -0
- data/lib/tamara/json_schemas/types/string.rb +21 -0
- data/lib/tamara/json_schemas/types/url.rb +15 -0
- data/lib/tamara/json_schemas/types/uuid.rb +19 -0
- data/lib/tamara/json_schemas/validator.rb +66 -0
- data/lib/tamara/json_schemas/webhook.rb +33 -0
- data/lib/tamara/json_schemas/webhook_event.rb +37 -0
- data/lib/tamara/version.rb +3 -0
- data/lib/tamara.rb +101 -0
- data/sig/tamara.rbs +4 -0
- metadata +181 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
module Tamara
|
2
|
+
class PaymentTypes < ApplicationService
|
3
|
+
include Tamara::JsonSchemas::PaymentTypes
|
4
|
+
|
5
|
+
def self.list(country: "SA", order_value: 1, opts: {})
|
6
|
+
new(country: country, order_value: order_value, opts: opts).call
|
7
|
+
end
|
8
|
+
|
9
|
+
def call_api
|
10
|
+
::Faraday.get(url, api_params, headers)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def url
|
16
|
+
"#{Tamara.checkout_uri}/payment-types"
|
17
|
+
end
|
18
|
+
|
19
|
+
def api_params
|
20
|
+
@api_params ||= { country: @params[:country], order_value: @params[:order_value] }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Tamara
|
2
|
+
module Payments
|
3
|
+
class Capture < ApplicationService
|
4
|
+
include Tamara::JsonSchemas::Payments::Capture
|
5
|
+
|
6
|
+
def self.call(order_id:, total_amount:, shipping_info:, items: [], shipping_amount: nil, tax_amount: nil, discount_amount: nil, opts: {})
|
7
|
+
new(order_id: order_id,
|
8
|
+
total_amount: total_amount,
|
9
|
+
shipping_info: shipping_info,
|
10
|
+
items: items,
|
11
|
+
shipping_amount: shipping_amount,
|
12
|
+
tax_amount: tax_amount,
|
13
|
+
discount_amount: discount_amount,
|
14
|
+
opts: opts).call
|
15
|
+
end
|
16
|
+
|
17
|
+
def call_api
|
18
|
+
::Faraday.post(url, api_params.to_json, headers)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def url
|
24
|
+
"#{Tamara.payments_uri}/capture"
|
25
|
+
end
|
26
|
+
|
27
|
+
def api_params
|
28
|
+
@api_params ||= {
|
29
|
+
order_id: @params[:order_id],
|
30
|
+
total_amount: @params[:total_amount],
|
31
|
+
shipping_info: @params[:shipping_info],
|
32
|
+
items: @params[:items],
|
33
|
+
shipping_amount: @params[:shipping_amount],
|
34
|
+
tax_amount: @params[:tax_amount],
|
35
|
+
discount_amount: @params[:discount_amount]
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Tamara
|
2
|
+
module Payments
|
3
|
+
def self.capture(order_id:, total_amount:, shipping_info:, items: [], shipping_amount: nil, tax_amount: nil, discount_amount: nil, opts: {})
|
4
|
+
Tamara::Payments::Capture.call(
|
5
|
+
order_id: order_id,
|
6
|
+
total_amount: total_amount,
|
7
|
+
shipping_info: shipping_info,
|
8
|
+
shipping_amount: shipping_amount,
|
9
|
+
tax_amount: tax_amount,
|
10
|
+
discount_amount: discount_amount,
|
11
|
+
items: items,
|
12
|
+
opts: opts
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Tamara
|
2
|
+
module Request
|
3
|
+
def headers
|
4
|
+
@headers = {
|
5
|
+
"Content-Type": "application/json",
|
6
|
+
Authorization: "Bearer #{api_token}"
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
def api_token
|
11
|
+
@opts[:api_token] || Tamara.api_token || Tamara.configuration.api_token
|
12
|
+
end
|
13
|
+
|
14
|
+
def parsed_response
|
15
|
+
@parsed_response ||= begin
|
16
|
+
JSON.parse(@response.body)
|
17
|
+
rescue StandardError
|
18
|
+
{}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def error_message
|
23
|
+
@error_message = parsed_response[:message]
|
24
|
+
end
|
25
|
+
|
26
|
+
def response_status
|
27
|
+
@response_status = @response.status
|
28
|
+
end
|
29
|
+
|
30
|
+
def response_body
|
31
|
+
@response_body = @response.body
|
32
|
+
end
|
33
|
+
|
34
|
+
# rubocop:disable Metrics/AbcSize
|
35
|
+
def handle_response_error
|
36
|
+
case response_status
|
37
|
+
when 400
|
38
|
+
raise InvalidRequestError.new(error_message, parsed_response.dig(:errors, 0, :error_code), http_status: response_status, http_body: response_body)
|
39
|
+
when 401
|
40
|
+
raise AuthenticationError.new("Invalid API key", http_status: response_status, http_body: response_body)
|
41
|
+
when 404
|
42
|
+
raise APIError.new("Resource not found", http_status: response_status, http_body: response_body)
|
43
|
+
when (400..599)
|
44
|
+
raise APIError.new(error_message, http_status: response_status, http_body: response_body)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
# rubocop:enable Metrics/AbcSize
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "jwt"
|
2
|
+
|
3
|
+
module Tamara
|
4
|
+
class Signature < ApplicationService
|
5
|
+
def self.verify(token, opts: {})
|
6
|
+
new(token: token, opts: opts).call
|
7
|
+
end
|
8
|
+
|
9
|
+
def call
|
10
|
+
begin
|
11
|
+
decoded = ::JWT.decode(@params[:token], notification_token, true, { algorithm: "HS256" })
|
12
|
+
rescue StandardError => e
|
13
|
+
return failure(e.message)
|
14
|
+
end
|
15
|
+
|
16
|
+
success(decoded)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def notification_token
|
22
|
+
@opts[:notification_token] || Tamara.notification_token || Tamara.configuration.notification_token
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Tamara
|
2
|
+
class Webhooks < ApplicationService
|
3
|
+
include Tamara::JsonSchemas::Webhook
|
4
|
+
|
5
|
+
def self.register(type:, events:, url:, headers: {}, opts: {})
|
6
|
+
new(type: type, events: events, url: url, headers: headers, opts: opts).call
|
7
|
+
end
|
8
|
+
|
9
|
+
def call_api
|
10
|
+
::Faraday.post(url, api_params.to_json, headers)
|
11
|
+
end
|
12
|
+
|
13
|
+
def url
|
14
|
+
Tamara.webhooks_uri
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def api_params
|
20
|
+
@api_params ||= {
|
21
|
+
type: @params[:type],
|
22
|
+
events: @params[:events],
|
23
|
+
url: @params[:url],
|
24
|
+
headers: @params[:headers]
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Tamara
|
2
|
+
# TamaraError is the base error from which all other more specific Tamara
|
3
|
+
# errors derive.
|
4
|
+
class TamaraError < StandardError
|
5
|
+
attr_reader :message, :error, :http_body, :http_headers, :http_status, :json_body
|
6
|
+
|
7
|
+
# Initializes a TamaraError.
|
8
|
+
def initialize(message = nil, http_status: nil, http_body: nil)
|
9
|
+
@message = message || http_body
|
10
|
+
@http_status = http_status
|
11
|
+
@http_body = http_body
|
12
|
+
begin
|
13
|
+
@json_body = JSON.parse(http_body)
|
14
|
+
rescue StandardError
|
15
|
+
@json_body = nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
|
21
|
+
"#{status_string}#{@message}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# ConfigurationMissingError is raised when a configuration is missing
|
26
|
+
class ConfigurationMissingError < StandardError; end
|
27
|
+
|
28
|
+
# AuthenticationError is raised when invalid credentials are used to connect
|
29
|
+
# to Tamara's servers.
|
30
|
+
class AuthenticationError < TamaraError
|
31
|
+
end
|
32
|
+
|
33
|
+
# APIConnectionError is raised in the event that the SDK can't connect to
|
34
|
+
# Tamara's servers. That can be for a variety of different reasons from a
|
35
|
+
# downed network to a bad TLS certificate.
|
36
|
+
class APIConnectionError < TamaraError
|
37
|
+
end
|
38
|
+
|
39
|
+
# APIError is a generic error that may be raised in cases where none of the
|
40
|
+
# other named errors cover the problem. It could also be raised in the case
|
41
|
+
# that a new error has been introduced in the API, but this version of the
|
42
|
+
# Ruby SDK doesn't know how to handle it.
|
43
|
+
class APIError < TamaraError
|
44
|
+
end
|
45
|
+
|
46
|
+
# InvalidRequestError is raised when a request is initiated with invalid
|
47
|
+
# parameters.
|
48
|
+
class InvalidRequestError < TamaraError
|
49
|
+
attr_accessor :param
|
50
|
+
|
51
|
+
def initialize(message, param, http_status: nil, http_body: nil)
|
52
|
+
super(message, http_status: http_status, http_body: http_body)
|
53
|
+
@param = param
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# SignatureVerificationError is raised when the signature verification for a
|
58
|
+
# webhook fails
|
59
|
+
class SignatureVerificationError < TamaraError
|
60
|
+
attr_accessor :sig_header
|
61
|
+
|
62
|
+
def initialize(message, sig_header, http_body: nil)
|
63
|
+
super(message, http_body: http_body)
|
64
|
+
@sig_header = sig_header
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/tamara/hmac.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Tamara
|
2
|
+
module Hmac
|
3
|
+
FILTERED_TRANSACTION_KEYS = %w[amount_cents created_at currency error_occured has_parent_transaction id
|
4
|
+
integration_id is_3d_secure is_auth is_capture is_refunded is_standalone_payment
|
5
|
+
is_voided order.id owner pending
|
6
|
+
source_data.pansource_data.sub_type source_data.type success].freeze
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def valid_signature?(tamara_response)
|
10
|
+
digest = ::OpenSSL::Digest.new("sha512")
|
11
|
+
|
12
|
+
concatenated_str = FILTERED_TRANSACTION_KEYS.map do |element|
|
13
|
+
tamara_response.dig("obj", *element.split("."))
|
14
|
+
end.join
|
15
|
+
secure_hash = ::OpenSSL::HMAC.hexdigest(digest, Tamara.hmac_key, concatenated_str)
|
16
|
+
secure_hash == tamara_response["hmac"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Tamara
|
2
|
+
module JsonSchemas
|
3
|
+
module Address
|
4
|
+
def self.schema(allows_null: false)
|
5
|
+
{
|
6
|
+
"$schema": "http://json-schema.org/draft-06/schema",
|
7
|
+
type: ["object", (allows_null ? "null" : nil)].compact,
|
8
|
+
properties: {
|
9
|
+
city: Types::String.schema,
|
10
|
+
country_code: Types::Enum.schema(values: COUNTRY_CODES, default: "SA"),
|
11
|
+
first_name: Types::String.schema,
|
12
|
+
last_name: Types::String.schema,
|
13
|
+
line1: Types::String.schema,
|
14
|
+
line2: Types::String.schema(allows_null: true),
|
15
|
+
phone_number: Types::String.schema(allows_null: true),
|
16
|
+
region: Types::String.schema(allows_null: true)
|
17
|
+
},
|
18
|
+
required: %w[city country_code first_name last_name line1]
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Tamara
|
2
|
+
module JsonSchemas
|
3
|
+
module Amount
|
4
|
+
CURRENCIES = %w[SAR AED BHD KWD OMR].freeze
|
5
|
+
|
6
|
+
def self.schema(allows_null: false)
|
7
|
+
{
|
8
|
+
"$schema": "http://json-schema.org/draft-06/schema",
|
9
|
+
type: ["object", (allows_null ? "null" : nil)].compact,
|
10
|
+
properties: {
|
11
|
+
amount: Types::Float.schema(min: 0.1),
|
12
|
+
currency: Types::Enum.schema(values: CURRENCIES, default: "SAR")
|
13
|
+
},
|
14
|
+
required: %w[amount currency]
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Tamara
|
2
|
+
module JsonSchemas
|
3
|
+
module CheckoutOptionalKeys
|
4
|
+
def checkout_optional_keys
|
5
|
+
@params ||= {}
|
6
|
+
checkout_optional_keys = @params.dig(:opts, :checkout_optional_keys) || Tamara.configuration.checkout_optional_keys
|
7
|
+
checkout_optional_keys.is_a?(Hash) ? checkout_optional_keys : {}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Tamara
|
2
|
+
module JsonSchemas
|
3
|
+
module Consumer
|
4
|
+
def self.schema(allows_null: false)
|
5
|
+
{
|
6
|
+
"$schema": "http://json-schema.org/draft-06/schema",
|
7
|
+
type: ["object", (allows_null ? "null" : nil)].compact,
|
8
|
+
properties: {
|
9
|
+
first_name: Types::String.schema,
|
10
|
+
last_name: Types::String.schema,
|
11
|
+
email: {
|
12
|
+
pattern: URI::MailTo::EMAIL_REGEXP
|
13
|
+
},
|
14
|
+
phone_number: Types::String.schema
|
15
|
+
},
|
16
|
+
required: %w[first_name last_name email phone_number]
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Tamara
|
2
|
+
module JsonSchemas
|
3
|
+
module Discount
|
4
|
+
def self.schema(allows_null: false)
|
5
|
+
{
|
6
|
+
"$schema": "http://json-schema.org/draft-06/schema",
|
7
|
+
type: ["object", (allows_null ? "null" : nil)].compact,
|
8
|
+
properties: {
|
9
|
+
name: Types::String.schema,
|
10
|
+
amount: Amount.schema
|
11
|
+
},
|
12
|
+
required: %w[name amount]
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Tamara
|
2
|
+
module JsonSchemas
|
3
|
+
module Item
|
4
|
+
extend CheckoutOptionalKeys
|
5
|
+
|
6
|
+
REQUIRED_KEYS = %w[name quantity reference_id type sku total_amount].freeze
|
7
|
+
|
8
|
+
# rubocop:disable Metrics/AbcSize
|
9
|
+
def self.schema(params = nil)
|
10
|
+
@params = params
|
11
|
+
{
|
12
|
+
"$schema": "http://json-schema.org/draft-06/schema",
|
13
|
+
type: "object",
|
14
|
+
properties: {
|
15
|
+
name: Types::String.schema(allows_null: filtered_keys.exclude?("name")),
|
16
|
+
quantity: Types::Integer.schema(min: 1, allows_null: filtered_keys.exclude?("quantity")),
|
17
|
+
reference_id: Types::String.schema(allows_null: filtered_keys.exclude?("reference_id")),
|
18
|
+
type: Types::String.schema(allows_null: filtered_keys.exclude?("type")),
|
19
|
+
sku: Types::String.schema(max_length: 128, allows_null: filtered_keys.exclude?("sku")),
|
20
|
+
item_url: Types::Url.schema(allows_null: filtered_keys.exclude?("item_url")),
|
21
|
+
image_url: Types::Url.schema(allows_null: filtered_keys.exclude?("image_url")),
|
22
|
+
unit_price: Amount.schema(allows_null: filtered_keys.exclude?("unit_price")),
|
23
|
+
tax_amount: Amount.schema(allows_null: filtered_keys.exclude?("tax_amount")),
|
24
|
+
discount_amount: Amount.schema(allows_null: filtered_keys.exclude?("discount_amount")),
|
25
|
+
total_amount: Amount.schema(allows_null: filtered_keys.exclude?("total_amount"))
|
26
|
+
},
|
27
|
+
required: filtered_keys
|
28
|
+
}
|
29
|
+
end
|
30
|
+
# rubocop:enable Metrics/AbcSize
|
31
|
+
|
32
|
+
def self.filtered_keys
|
33
|
+
@filtered_keys ||= begin
|
34
|
+
optional_keys = (checkout_optional_keys[:items] || []).map(&:to_s)
|
35
|
+
|
36
|
+
REQUIRED_KEYS - optional_keys
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Tamara
|
2
|
+
module JsonSchemas
|
3
|
+
module MerchantUrl
|
4
|
+
def self.schema(allows_null: false)
|
5
|
+
{
|
6
|
+
"$schema": "http://json-schema.org/draft-06/schema",
|
7
|
+
type: ["object", (allows_null ? "null" : nil)].compact,
|
8
|
+
properties: {
|
9
|
+
cancel: Types::Url.schema,
|
10
|
+
failure: Types::Url.schema,
|
11
|
+
success: Types::Url.schema,
|
12
|
+
notification: Types::Url.schema(allows_null: true)
|
13
|
+
},
|
14
|
+
required: %w[cancel failure success]
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Tamara
|
2
|
+
module JsonSchemas
|
3
|
+
module Orders
|
4
|
+
module Cancel
|
5
|
+
include Validator
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def schema
|
10
|
+
{
|
11
|
+
"$schema": "http://json-schema.org/draft-06/schema",
|
12
|
+
type: "object",
|
13
|
+
properties: {
|
14
|
+
order_id: Types::Uuid.schema,
|
15
|
+
total_amount: Amount.schema,
|
16
|
+
shipping_amount: Amount.schema(allows_null: true),
|
17
|
+
tax_amount: Amount.schema(allows_null: true),
|
18
|
+
discount_amount: Amount.schema(allows_null: true),
|
19
|
+
items: {
|
20
|
+
type: "array",
|
21
|
+
items: Item.schema
|
22
|
+
}
|
23
|
+
},
|
24
|
+
required: %w[order_id total_amount]
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Tamara
|
2
|
+
module JsonSchemas
|
3
|
+
module Orders
|
4
|
+
module Create
|
5
|
+
include CheckoutOptionalKeys
|
6
|
+
include Validator
|
7
|
+
|
8
|
+
PAYMENT_TYPES = %w[PAY_BY_INSTALMENTS PAY_NOW].freeze
|
9
|
+
LOCALES = %w[ar_SA en_US].freeze
|
10
|
+
|
11
|
+
REQUIRED_KEYS = %w[order_reference_id country_code description total_amount shipping_amount tax_amount
|
12
|
+
consumer items merchant_url shipping_address payment_type instalments risk_assessment].freeze
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# rubocop:disable Metrics/AbcSize
|
17
|
+
def schema
|
18
|
+
{
|
19
|
+
"$schema": "http://json-schema.org/draft-06/schema",
|
20
|
+
type: "object",
|
21
|
+
properties: {
|
22
|
+
order_reference_id: Types::String.schema(allows_null: filtered_keys.exclude?("order_reference_id")),
|
23
|
+
country_code: Types::Enum.schema(values: COUNTRY_CODES, default: "SA"),
|
24
|
+
description: Types::String.schema(max_length: 256, allows_null: filtered_keys.exclude?("description")),
|
25
|
+
total_amount: Amount.schema(allows_null: filtered_keys.exclude?("total_amount")),
|
26
|
+
shipping_amount: Amount.schema(allows_null: filtered_keys.exclude?("shipping_amount")),
|
27
|
+
tax_amount: Amount.schema(allows_null: filtered_keys.exclude?("tax_amount")),
|
28
|
+
consumer: Consumer.schema(allows_null: filtered_keys.exclude?("consumer")),
|
29
|
+
items: {
|
30
|
+
type: "array",
|
31
|
+
minItems: 1,
|
32
|
+
items: Item.schema(@params)
|
33
|
+
},
|
34
|
+
merchant_url: MerchantUrl.schema(allows_null: filtered_keys.exclude?("merchant_url")),
|
35
|
+
shipping_address: Address.schema(allows_null: filtered_keys.exclude?("shipping_address")),
|
36
|
+
payment_type: Types::Enum.schema(values: PAYMENT_TYPES, default: "PAY_BY_INSTALMENTS"),
|
37
|
+
instalments: Types::Integer.schema(min: 1, default: 3),
|
38
|
+
order_number: Types::String.schema(allows_null: filtered_keys.exclude?("order_number")),
|
39
|
+
discount: Discount.schema(allows_null: true),
|
40
|
+
billing_address: Address.schema(allows_null: true),
|
41
|
+
platform: Types::String.schema(allows_null: true),
|
42
|
+
is_mobile: Types::Boolean.schema(default: false),
|
43
|
+
locale: Types::Enum.schema(values: LOCALES, default: "ar_SA"),
|
44
|
+
expires_in_minutes: Types::Integer.schema(min: 5, max: 1440, default: 30),
|
45
|
+
risk_assessment: RiskAssessment.schema(allows_null: filtered_keys.exclude?("risk_assessment"), params: @params)
|
46
|
+
},
|
47
|
+
required: filtered_keys
|
48
|
+
}
|
49
|
+
end
|
50
|
+
# rubocop:enable Metrics/AbcSize
|
51
|
+
|
52
|
+
def filtered_keys
|
53
|
+
@filtered_keys ||= begin
|
54
|
+
optional_keys = checkout_optional_keys.select { |_k, v| v.empty? }.keys.map(&:to_s)
|
55
|
+
REQUIRED_KEYS - optional_keys
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Tamara
|
2
|
+
module JsonSchemas
|
3
|
+
module PaymentOptions
|
4
|
+
module Check
|
5
|
+
include Validator
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def schema
|
10
|
+
{
|
11
|
+
"$schema": "http://json-schema.org/draft-06/schema",
|
12
|
+
type: "object",
|
13
|
+
properties: {
|
14
|
+
country: Types::Enum.schema(values: COUNTRY_CODES, default: "SA"),
|
15
|
+
phone_number: Types::String.schema,
|
16
|
+
order_value: Amount.schema,
|
17
|
+
is_vip: Types::Boolean.schema(default: false)
|
18
|
+
},
|
19
|
+
required: %w[country phone_number order_value]
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Tamara
|
2
|
+
module JsonSchemas
|
3
|
+
module PaymentTypes
|
4
|
+
include Validator
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def schema
|
9
|
+
{
|
10
|
+
"$schema": "http://json-schema.org/draft-06/schema",
|
11
|
+
type: "object",
|
12
|
+
properties: {
|
13
|
+
country: Types::Enum.schema(values: COUNTRY_CODES, default: "SA"),
|
14
|
+
order_value: Types::Float.schema(min: 0.1)
|
15
|
+
},
|
16
|
+
required: %w[country order_value]
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Tamara
|
2
|
+
module JsonSchemas
|
3
|
+
module Payments
|
4
|
+
module Capture
|
5
|
+
include Validator
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def schema
|
10
|
+
{
|
11
|
+
"$schema": "http://json-schema.org/draft-06/schema",
|
12
|
+
type: "object",
|
13
|
+
properties: {
|
14
|
+
order_id: Types::Uuid.schema,
|
15
|
+
total_amount: Amount.schema,
|
16
|
+
shipping_info: {
|
17
|
+
type: "object",
|
18
|
+
properties: {
|
19
|
+
shipped_at: Types::String.schema,
|
20
|
+
shipping_company: Types::String.schema
|
21
|
+
},
|
22
|
+
required: %w[shipped_at shipping_company]
|
23
|
+
},
|
24
|
+
items: {
|
25
|
+
type: "array",
|
26
|
+
items: Item.schema
|
27
|
+
},
|
28
|
+
shipping_amount: Amount.schema(allows_null: true),
|
29
|
+
tax_amount: Amount.schema(allows_null: true),
|
30
|
+
discount_amount: Amount.schema(allows_null: true)
|
31
|
+
},
|
32
|
+
required: %w[order_id total_amount shipping_info]
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|