metrifox-sdk 1.0.1
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/CHANGELOG.md +12 -0
- data/LICENSE +21 -0
- data/README.md +171 -0
- data/lib/metrifox-sdk.rb +16 -0
- data/lib/metrifox_sdk/base_api.rb +76 -0
- data/lib/metrifox_sdk/base_module.rb +27 -0
- data/lib/metrifox_sdk/client.rb +31 -0
- data/lib/metrifox_sdk/customers/api.rb +82 -0
- data/lib/metrifox_sdk/customers/module.rb +44 -0
- data/lib/metrifox_sdk/types.rb +111 -0
- data/lib/metrifox_sdk/usages/api.rb +70 -0
- data/lib/metrifox_sdk/usages/module.rb +34 -0
- data/lib/metrifox_sdk/util_methods.rb +29 -0
- data/lib/metrifox_sdk/version.rb +3 -0
- metadata +158 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f814153e75795c0d87de3d15f3164f73fc6a561be992a209900880d2b8461406
|
4
|
+
data.tar.gz: 5329b40387f7555df0895e7889f0e5f63b52b854571d34816627d159340bccd5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0efde0b9967198c7f0631b7bd35343f00fa94c56d8cfde2696eb7b6f4405ca6995adb82776f5ea516a6f5e40d132ff1023690e4c0526560ad429879a1dfc605a
|
7
|
+
data.tar.gz: 7c14771a87ad8032448a53d38b20e3ed94fb423c4b674897c9263408cc4693fcfd7033931c1ac66e53c0c962dda0f92f29841aa8b9a35065a1512fd496aa11b1
|
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Your Name
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
# MetrifoxSDK Ruby Gem
|
2
|
+
|
3
|
+
A Ruby SDK for interacting with the Metrifox platform API.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'metrifox_sdk'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
```bash
|
16
|
+
$ bundle install
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
$ gem install metrifox_sdk
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### Configuration
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'metrifox_sdk'
|
31
|
+
|
32
|
+
# Initialize with configuration
|
33
|
+
MetrifoxSDK.init({
|
34
|
+
api_key: "your-api-key",
|
35
|
+
base_url: "https://metrifox-api.staging.useyala.com/api/v1/",
|
36
|
+
web_app_base_url: "https://frontend-v3.staging.useyala.com"
|
37
|
+
})
|
38
|
+
|
39
|
+
# Or set environment variable
|
40
|
+
ENV["METRIFOX_API_KEY"] = "your-api-key"
|
41
|
+
MetrifoxSDK.init
|
42
|
+
```
|
43
|
+
|
44
|
+
### Access Control
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
# Check feature access
|
48
|
+
response = MetrifoxSDK.usages.check_access({
|
49
|
+
feature_key: "premium_feature",
|
50
|
+
customer_key: "customer_123"
|
51
|
+
})
|
52
|
+
|
53
|
+
puts response["can_access"] # true/false
|
54
|
+
```
|
55
|
+
|
56
|
+
### Usage Tracking
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
# Record usage event
|
60
|
+
response = MetrifoxSDK.usages.record_usage({
|
61
|
+
customer_key: "customer_123",
|
62
|
+
event_name: "api_call",
|
63
|
+
amount: 1
|
64
|
+
})
|
65
|
+
```
|
66
|
+
|
67
|
+
### Customer Management
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
# Create customer
|
71
|
+
customer_data = {
|
72
|
+
customer_key: "customer_123",
|
73
|
+
customer_type: "BUSINESS",
|
74
|
+
primary_email: "customer@example.com",
|
75
|
+
legal_name: "Acme Corp",
|
76
|
+
display_name: "ACME"
|
77
|
+
}
|
78
|
+
|
79
|
+
response = MetrifoxSDK.customers.create(customer_data)
|
80
|
+
|
81
|
+
# Update customer
|
82
|
+
update_data = {
|
83
|
+
display_name: "ACME Corporation",
|
84
|
+
website_url: "https://acme.com"
|
85
|
+
}
|
86
|
+
|
87
|
+
response = MetrifoxSDK.customers.update("customer_123", update_data)
|
88
|
+
|
89
|
+
# Get customer
|
90
|
+
response = MetrifoxSDK.customers.get_customer({ customer_key: "customer_123" })
|
91
|
+
|
92
|
+
# Get customer details
|
93
|
+
response = MetrifoxSDK.customers.get_details({ customer_key: "customer_123" })
|
94
|
+
|
95
|
+
# Delete customer
|
96
|
+
response = MetrifoxSDK.delete_customer({ customer_key: "customer_123" })
|
97
|
+
```
|
98
|
+
|
99
|
+
### CSV Upload
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
# Upload customers via CSV
|
103
|
+
response = MetrifoxSDK.customers.upload_csv("/path/to/customers.csv")
|
104
|
+
|
105
|
+
puts response["data"]["total_customers"]
|
106
|
+
puts response["data"]["successful_upload_count"]
|
107
|
+
```
|
108
|
+
|
109
|
+
### Using Client Instance
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
client = MetrifoxSDK::Client.new({
|
113
|
+
api_key: "your-api-key"
|
114
|
+
})
|
115
|
+
|
116
|
+
response = client.usages.check_access({
|
117
|
+
feature_key: "premium_feature",
|
118
|
+
customer_key: "customer_123"
|
119
|
+
})
|
120
|
+
```
|
121
|
+
|
122
|
+
## Type Safety with Structs
|
123
|
+
|
124
|
+
The SDK provides structured types for better type safety:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
# Using structured request objects
|
128
|
+
access_request = MetrifoxSDK::Types::AccessCheckRequest.new(
|
129
|
+
feature_key: "premium_feature",
|
130
|
+
customer_key: "customer_123"
|
131
|
+
)
|
132
|
+
|
133
|
+
response = MetrifoxSDK.usages.check_access(access_request)
|
134
|
+
|
135
|
+
# Customer creation with structured data
|
136
|
+
customer_request = MetrifoxSDK::Types::CustomerCreateRequest.new(
|
137
|
+
customer_key: "customer_123",
|
138
|
+
customer_type: MetrifoxSDK::Types::CustomerType::BUSINESS,
|
139
|
+
primary_email: "customer@example.com",
|
140
|
+
legal_name: "Acme Corp"
|
141
|
+
)
|
142
|
+
|
143
|
+
response = MetrifoxSDK.customers.create(customer_request)
|
144
|
+
```
|
145
|
+
|
146
|
+
## Error Handling
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
begin
|
150
|
+
response = MetrifoxSDK.usages.check_access({
|
151
|
+
feature_key: "premium_feature",
|
152
|
+
customer_key: "customer_123"
|
153
|
+
})
|
154
|
+
rescue MetrifoxSDK::APIError => e
|
155
|
+
puts "API Error: #{e.message}"
|
156
|
+
rescue MetrifoxSDK::ConfigurationError => e
|
157
|
+
puts "Configuration Error: #{e.message}"
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
161
|
+
## Development
|
162
|
+
|
163
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
164
|
+
|
165
|
+
## Contributing
|
166
|
+
|
167
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/yourusername/metrifox_ruby_sdk.
|
168
|
+
|
169
|
+
## License
|
170
|
+
|
171
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/lib/metrifox-sdk.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative "metrifox_sdk/version"
|
2
|
+
require_relative "metrifox_sdk/client"
|
3
|
+
require_relative "metrifox_sdk/types"
|
4
|
+
require_relative "metrifox_sdk/util_methods"
|
5
|
+
require_relative "metrifox_sdk/base_api"
|
6
|
+
require_relative "metrifox_sdk/base_module"
|
7
|
+
require_relative "metrifox_sdk/customers/module"
|
8
|
+
require_relative "metrifox_sdk/usages/module"
|
9
|
+
|
10
|
+
module MetrifoxSDK
|
11
|
+
class << self
|
12
|
+
def init(config = {})
|
13
|
+
Client.new(config)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "uri"
|
3
|
+
require "json"
|
4
|
+
require "mime/types"
|
5
|
+
|
6
|
+
module MetrifoxSDK
|
7
|
+
class BaseApi
|
8
|
+
private
|
9
|
+
|
10
|
+
def make_request(uri, method, api_key, body = nil)
|
11
|
+
headers = {
|
12
|
+
"x-api-key" => api_key,
|
13
|
+
"Content-Type" => "application/json"
|
14
|
+
}
|
15
|
+
|
16
|
+
body_json = body ? JSON.generate(body) : nil
|
17
|
+
make_raw_request(uri, method, headers, body_json)
|
18
|
+
end
|
19
|
+
|
20
|
+
def make_raw_request(uri, method, headers, body = nil)
|
21
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
22
|
+
http.use_ssl = uri.scheme == "https"
|
23
|
+
|
24
|
+
request = case method
|
25
|
+
when "GET"
|
26
|
+
Net::HTTP::Get.new(uri)
|
27
|
+
when "POST"
|
28
|
+
Net::HTTP::Post.new(uri)
|
29
|
+
when "PATCH"
|
30
|
+
Net::HTTP::Patch.new(uri)
|
31
|
+
when "DELETE"
|
32
|
+
Net::HTTP::Delete.new(uri)
|
33
|
+
else
|
34
|
+
raise ArgumentError, "Unsupported HTTP method: #{method}"
|
35
|
+
end
|
36
|
+
|
37
|
+
headers.each { |key, value| request[key] = value }
|
38
|
+
request.body = body if body
|
39
|
+
|
40
|
+
http.request(request)
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_response(response, error_message)
|
44
|
+
unless response.is_a?(Net::HTTPSuccess)
|
45
|
+
raise APIError, "#{error_message}: #{response.code} #{response.message}"
|
46
|
+
end
|
47
|
+
|
48
|
+
JSON.parse(response.body)
|
49
|
+
rescue JSON::ParserError => e
|
50
|
+
raise APIError, "Invalid JSON response: #{e.message}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_multipart_body(file_path, boundary)
|
54
|
+
unless File.exist?(file_path)
|
55
|
+
raise ArgumentError, "File not found: #{file_path}"
|
56
|
+
end
|
57
|
+
|
58
|
+
file_content = File.read(file_path)
|
59
|
+
filename = File.basename(file_path)
|
60
|
+
mime_type = MIME::Types.type_for(filename).first&.content_type || "text/csv"
|
61
|
+
|
62
|
+
body = []
|
63
|
+
body << "--#{boundary}"
|
64
|
+
body << 'Content-Disposition: form-data; name="csv"; filename="' + filename + '"'
|
65
|
+
body << "Content-Type: #{mime_type}"
|
66
|
+
body << ""
|
67
|
+
body << file_content
|
68
|
+
body << "--#{boundary}--"
|
69
|
+
body << ""
|
70
|
+
|
71
|
+
body.join("\r\n")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class APIError < StandardError; end
|
76
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module MetrifoxSDK
|
2
|
+
class BaseModule
|
3
|
+
attr_reader :client
|
4
|
+
|
5
|
+
def initialize(client)
|
6
|
+
@client = client
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def api_key
|
12
|
+
@client.api_key
|
13
|
+
end
|
14
|
+
|
15
|
+
def base_url
|
16
|
+
@client.base_url
|
17
|
+
end
|
18
|
+
|
19
|
+
def validate_api_key!
|
20
|
+
if api_key.nil? || api_key.empty?
|
21
|
+
raise ConfigurationError, "API key required. Set it via config or METRIFOX_API_KEY environment variable."
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class ConfigurationError < StandardError; end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative './util_methods'
|
2
|
+
|
3
|
+
module MetrifoxSDK
|
4
|
+
class Client
|
5
|
+
include MetrifoxSDK::UtilMethods
|
6
|
+
|
7
|
+
attr_reader :config, :api_key, :base_url, :web_app_base_url
|
8
|
+
|
9
|
+
def initialize(config = {})
|
10
|
+
@config = config
|
11
|
+
@api_key = config[:api_key] || get_api_key_from_environment
|
12
|
+
@base_url = config[:base_url] || "https://api.metrifox.com/api/v1/"
|
13
|
+
@web_app_base_url = config[:web_app_base_url] || "https://app.metrifox.com"
|
14
|
+
end
|
15
|
+
|
16
|
+
def customers
|
17
|
+
@customers ||= Customers::Module.new(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
def usages
|
21
|
+
@usages ||= Usages::Module.new(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def get_api_key_from_environment
|
27
|
+
MetrifoxSDK::UtilMethods.load_dotenv
|
28
|
+
ENV["METRIFOX_API_KEY"] || ""
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "uri"
|
3
|
+
require "json"
|
4
|
+
require "mime/types"
|
5
|
+
require_relative "../base_api"
|
6
|
+
|
7
|
+
module MetrifoxSDK::Customers
|
8
|
+
class API < MetrifoxSDK::BaseApi
|
9
|
+
def customer_create_request(base_url, api_key, request_payload)
|
10
|
+
uri = URI.join(base_url, "customers/new")
|
11
|
+
body = serialize_customer_request(request_payload)
|
12
|
+
response = make_request(uri, "POST", api_key, body)
|
13
|
+
parse_response(response, "Failed to Create Customer")
|
14
|
+
end
|
15
|
+
|
16
|
+
def customer_update_request(base_url, api_key, customer_key, request_payload)
|
17
|
+
uri = URI.join(base_url, "customers/#{customer_key}")
|
18
|
+
body = serialize_customer_request(request_payload)
|
19
|
+
response = make_request(uri, "PATCH", api_key, body)
|
20
|
+
parse_response(response, "Failed to UPDATE Customer")
|
21
|
+
end
|
22
|
+
|
23
|
+
def customer_delete_request(base_url, api_key, request_payload)
|
24
|
+
customer_key = get_value(request_payload, :customer_key)
|
25
|
+
uri = URI.join(base_url, "customers/#{customer_key}")
|
26
|
+
response = make_request(uri, "DELETE", api_key)
|
27
|
+
parse_response(response, "Failed to DELETE Customer")
|
28
|
+
end
|
29
|
+
|
30
|
+
def customer_get_request(base_url, api_key, request_payload)
|
31
|
+
customer_key = get_value(request_payload, :customer_key)
|
32
|
+
uri = URI.join(base_url, "customers/#{customer_key}")
|
33
|
+
response = make_request(uri, "GET", api_key)
|
34
|
+
parse_response(response, "Failed to Fetch Customer")
|
35
|
+
end
|
36
|
+
|
37
|
+
def customer_details_get_request(base_url, api_key, request_payload)
|
38
|
+
customer_key = get_value(request_payload, :customer_key)
|
39
|
+
uri = URI.join(base_url, "customers/#{customer_key}/details")
|
40
|
+
response = make_request(uri, "GET", api_key)
|
41
|
+
parse_response(response, "Failed to Fetch Customer Details")
|
42
|
+
end
|
43
|
+
|
44
|
+
def upload_customers_csv(base_url, api_key, file_path)
|
45
|
+
uri = URI.join(base_url, "customers/csv-upload")
|
46
|
+
|
47
|
+
boundary = "----WebKitFormBoundary#{Random.hex(16)}"
|
48
|
+
body = build_multipart_body(file_path, boundary)
|
49
|
+
|
50
|
+
headers = {
|
51
|
+
"x-api-key" => api_key,
|
52
|
+
"Content-Type" => "multipart/form-data; boundary=#{boundary}"
|
53
|
+
}
|
54
|
+
|
55
|
+
response = make_raw_request(uri, "POST", headers, body)
|
56
|
+
parse_response(response, "Failed to upload CSV")
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def serialize_customer_request(request)
|
62
|
+
if request.respond_to?(:to_h)
|
63
|
+
request.to_h.compact
|
64
|
+
elsif request.is_a?(Hash)
|
65
|
+
request.compact
|
66
|
+
else
|
67
|
+
raise ArgumentError, "Invalid request format"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Helper method to get value from either hash or struct
|
72
|
+
def get_value(object, key)
|
73
|
+
if object.respond_to?(key)
|
74
|
+
object.public_send(key)
|
75
|
+
elsif object.respond_to?(:[])
|
76
|
+
object[key] || object[key.to_s]
|
77
|
+
else
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative "api"
|
2
|
+
require_relative "../base_module"
|
3
|
+
|
4
|
+
module MetrifoxSDK
|
5
|
+
module Customers
|
6
|
+
class Module < BaseModule
|
7
|
+
def create(request_payload)
|
8
|
+
validate_api_key!
|
9
|
+
api.customer_create_request(base_url, api_key, request_payload)
|
10
|
+
end
|
11
|
+
|
12
|
+
def update(customer_key, request_payload)
|
13
|
+
validate_api_key!
|
14
|
+
api.customer_update_request(base_url, api_key, customer_key, request_payload)
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_customer(request_payload)
|
18
|
+
validate_api_key!
|
19
|
+
api.customer_get_request(base_url, api_key, request_payload)
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_details(request_payload)
|
23
|
+
validate_api_key!
|
24
|
+
api.customer_details_get_request(base_url, api_key, request_payload)
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete_customer(request_payload)
|
28
|
+
validate_api_key!
|
29
|
+
api.customer_delete_request(base_url, api_key, request_payload)
|
30
|
+
end
|
31
|
+
|
32
|
+
def upload_csv(file_path)
|
33
|
+
validate_api_key!
|
34
|
+
api.upload_customers_csv(base_url, api_key, file_path)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def api
|
40
|
+
@api ||= API.new
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module MetrifoxSDK
|
2
|
+
module Types
|
3
|
+
# Enums
|
4
|
+
module TaxStatus
|
5
|
+
TAXABLE = "TAXABLE"
|
6
|
+
TAX_EXEMPT = "TAX_EXEMPT"
|
7
|
+
REVERSE_CHARGE = "REVERSE_CHARGE"
|
8
|
+
end
|
9
|
+
|
10
|
+
module CustomerType
|
11
|
+
BUSINESS = "BUSINESS"
|
12
|
+
INDIVIDUAL = "INDIVIDUAL"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Value objects / Structs
|
16
|
+
EmailAddress = Struct.new(:email, :is_primary, keyword_init: true)
|
17
|
+
PhoneNumber = Struct.new(:phone_number, :country_code, :is_primary, keyword_init: true)
|
18
|
+
|
19
|
+
Address = Struct.new(
|
20
|
+
:country, :address_line_one, :address_line_two, :city,
|
21
|
+
:state, :zip_code, :phone_number, keyword_init: true
|
22
|
+
)
|
23
|
+
|
24
|
+
BillingConfig = Struct.new(
|
25
|
+
:preferred_payment_gateway, :preferred_payment_method, :billing_email,
|
26
|
+
:billing_address, :payment_reminder_days, keyword_init: true
|
27
|
+
)
|
28
|
+
|
29
|
+
TaxIdentification = Struct.new(:type, :number, :country, keyword_init: true)
|
30
|
+
|
31
|
+
ContactPerson = Struct.new(
|
32
|
+
:first_name, :last_name, :email_address, :designation,
|
33
|
+
:department, :is_primary, :phone_number, keyword_init: true
|
34
|
+
)
|
35
|
+
|
36
|
+
PaymentTerm = Struct.new(:type, :value, keyword_init: true)
|
37
|
+
|
38
|
+
# Request/Response objects
|
39
|
+
AccessCheckRequest = Struct.new(:feature_key, :customer_key, keyword_init: true)
|
40
|
+
|
41
|
+
AccessResponse = Struct.new(
|
42
|
+
:message, :can_access, :customer_id, :feature_key, :required_quantity,
|
43
|
+
:used_quantity, :included_usage, :next_reset_at, :quota, :unlimited,
|
44
|
+
:carryover_quantity, :balance, keyword_init: true
|
45
|
+
)
|
46
|
+
|
47
|
+
UsageEventRequest = Struct.new(:customer_key, :event_name, :amount, keyword_init: true) do
|
48
|
+
def initialize(customer_key:, event_name:, amount: 1)
|
49
|
+
super
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
UsageEventResponse = Struct.new(:message, :event_name, :customer_key, keyword_init: true)
|
54
|
+
|
55
|
+
CustomerCreateRequest = Struct.new(
|
56
|
+
# Core fields
|
57
|
+
:customer_key, :customer_type, :primary_email, :primary_phone,
|
58
|
+
# Business fields
|
59
|
+
:legal_name, :display_name, :legal_number, :tax_identification_number,
|
60
|
+
:logo_url, :website_url, :account_manager,
|
61
|
+
# Individual fields
|
62
|
+
:first_name, :middle_name, :last_name, :date_of_birth, :billing_email,
|
63
|
+
# Preferences
|
64
|
+
:timezone, :language, :currency, :tax_status,
|
65
|
+
# Address fields
|
66
|
+
:address_line1, :address_line2, :city, :state, :country, :zip_code,
|
67
|
+
# Shipping address fields
|
68
|
+
:shipping_address_line1, :shipping_address_line2, :shipping_city,
|
69
|
+
:shipping_state, :shipping_country, :shipping_zip_code,
|
70
|
+
# Complex fields
|
71
|
+
:billing_configuration, :tax_identifications, :contact_people,
|
72
|
+
:payment_terms, :metadata, keyword_init: true
|
73
|
+
)
|
74
|
+
|
75
|
+
CustomerUpdateRequest = Struct.new(
|
76
|
+
# Core fields
|
77
|
+
:customer_key, :customer_type, :primary_email, :primary_phone, :billing_email,
|
78
|
+
# Business fields
|
79
|
+
:legal_name, :display_name, :legal_number, :tax_identification_number,
|
80
|
+
:logo_url, :website_url, :account_manager,
|
81
|
+
# Individual fields
|
82
|
+
:first_name, :middle_name, :last_name, :date_of_birth,
|
83
|
+
# Preferences
|
84
|
+
:timezone, :language, :currency, :tax_status,
|
85
|
+
# Address fields
|
86
|
+
:address_line1, :address_line2, :city, :state, :country, :zip_code,
|
87
|
+
# Shipping address fields
|
88
|
+
:shipping_address_line1, :shipping_address_line2, :shipping_city,
|
89
|
+
:shipping_state, :shipping_country, :shipping_zip_code,
|
90
|
+
# Complex fields
|
91
|
+
:billing_configuration, :tax_identifications, :contact_people,
|
92
|
+
:payment_terms, :metadata, :phone_numbers, :email_addresses, keyword_init: true
|
93
|
+
)
|
94
|
+
|
95
|
+
CustomerDeleteRequest = Struct.new(:customer_key, keyword_init: true)
|
96
|
+
CustomerGetRequest = Struct.new(:customer_key, keyword_init: true)
|
97
|
+
|
98
|
+
CustomerCSVSyncResponse = Struct.new(
|
99
|
+
:status_code, :message, :data, :errors, :meta, keyword_init: true
|
100
|
+
) do
|
101
|
+
CSVSyncData = Struct.new(
|
102
|
+
:total_customers, :successful_upload_count, :failed_upload_count,
|
103
|
+
:customers_added, :customers_failed, keyword_init: true
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
107
|
+
APIResponse = Struct.new(:status_code, :message, :data, :errors, :meta, keyword_init: true)
|
108
|
+
|
109
|
+
EmbedConfig = Struct.new(:container, :product_key, keyword_init: true)
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "uri"
|
3
|
+
require "json"
|
4
|
+
require "mime/types"
|
5
|
+
require_relative "../base_api"
|
6
|
+
|
7
|
+
module MetrifoxSDK::Usages
|
8
|
+
class API < MetrifoxSDK::BaseApi
|
9
|
+
def fetch_access(base_url, api_key, request_payload)
|
10
|
+
uri = URI.join(base_url, "usage/access")
|
11
|
+
|
12
|
+
# Handle both hash and struct access patterns
|
13
|
+
feature_key = get_value(request_payload, :feature_key)
|
14
|
+
customer_key = get_value(request_payload, :customer_key)
|
15
|
+
|
16
|
+
uri.query = URI.encode_www_form({
|
17
|
+
feature_key: feature_key,
|
18
|
+
customer_key: customer_key
|
19
|
+
})
|
20
|
+
|
21
|
+
response = make_request(uri, "GET", api_key)
|
22
|
+
parse_response(response, "Failed to check access")
|
23
|
+
end
|
24
|
+
|
25
|
+
def fetch_usage(base_url, api_key, request_payload)
|
26
|
+
uri = URI.join(base_url, "usage/events")
|
27
|
+
|
28
|
+
# Handle both hash and struct access patterns
|
29
|
+
customer_key = get_value(request_payload, :customer_key)
|
30
|
+
event_name = get_value(request_payload, :event_name)
|
31
|
+
amount = get_value(request_payload, :amount) || 1
|
32
|
+
|
33
|
+
body = {
|
34
|
+
customer_key: customer_key,
|
35
|
+
event_name: event_name,
|
36
|
+
amount: amount
|
37
|
+
}
|
38
|
+
|
39
|
+
response = make_request(uri, "POST", api_key, body)
|
40
|
+
parse_response(response, "Failed to record usage")
|
41
|
+
end
|
42
|
+
|
43
|
+
def fetch_tenant_id(base_url, api_key)
|
44
|
+
uri = URI.join(base_url, "auth/get-tenant-id")
|
45
|
+
response = make_request(uri, "GET", api_key)
|
46
|
+
data = parse_response(response, "Failed to get tenant id")
|
47
|
+
data.dig("data", "tenant_id")
|
48
|
+
end
|
49
|
+
|
50
|
+
def fetch_checkout_key(base_url, api_key)
|
51
|
+
uri = URI.join(base_url, "auth/checkout-username")
|
52
|
+
response = make_request(uri, "GET", api_key)
|
53
|
+
data = parse_response(response, "Failed to get tenant checkout settings")
|
54
|
+
data.dig("data", "checkout_username")
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Helper method to get value from either hash or struct
|
60
|
+
def get_value(object, key)
|
61
|
+
if object.respond_to?(key)
|
62
|
+
object.public_send(key)
|
63
|
+
elsif object.respond_to?(:[])
|
64
|
+
object[key] || object[key.to_s]
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative "api"
|
2
|
+
require_relative "../base_module"
|
3
|
+
|
4
|
+
module MetrifoxSDK
|
5
|
+
module Usages
|
6
|
+
class Module < BaseModule
|
7
|
+
def check_access(request_payload)
|
8
|
+
validate_api_key!
|
9
|
+
api.fetch_access(base_url, api_key, request_payload)
|
10
|
+
end
|
11
|
+
|
12
|
+
def record_usage(request_payload)
|
13
|
+
validate_api_key!
|
14
|
+
api.fetch_usage(base_url, api_key, request_payload)
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_tenant_id
|
18
|
+
validate_api_key!
|
19
|
+
api.fetch_tenant_id(base_url, api_key)
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_checkout_key
|
23
|
+
validate_api_key!
|
24
|
+
api.fetch_checkout_key(base_url, api_key)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def api
|
30
|
+
@api ||= API.new
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module MetrifoxSDK
|
2
|
+
module UtilMethods
|
3
|
+
def self.load_dotenv
|
4
|
+
return if @dotenv_loaded
|
5
|
+
|
6
|
+
env_files = ['.env.local', '.env']
|
7
|
+
env_files.each do |file|
|
8
|
+
next unless File.exist?(file)
|
9
|
+
|
10
|
+
File.readlines(file).each do |line|
|
11
|
+
line = line.strip
|
12
|
+
next if line.empty? || line.start_with?('#')
|
13
|
+
|
14
|
+
key, value = line.split('=', 2)
|
15
|
+
next unless key && value
|
16
|
+
|
17
|
+
# Remove quotes if present
|
18
|
+
value = value.gsub(/\A['"]|['"]\z/, '')
|
19
|
+
|
20
|
+
# Only set if not already set (allows override)
|
21
|
+
ENV[key] ||= value
|
22
|
+
end
|
23
|
+
break # Use first found file
|
24
|
+
end
|
25
|
+
|
26
|
+
@dotenv_loaded = true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: metrifox-sdk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Metrifox
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-09-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mime-types
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: net-http
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: uri
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.12'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.12'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: dotenv
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.8'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.8'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
description: A Ruby SDK for interacting with the Metrifox platform API
|
112
|
+
email:
|
113
|
+
- abiodun@metrifox.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- CHANGELOG.md
|
119
|
+
- LICENSE
|
120
|
+
- README.md
|
121
|
+
- lib/metrifox-sdk.rb
|
122
|
+
- lib/metrifox_sdk/base_api.rb
|
123
|
+
- lib/metrifox_sdk/base_module.rb
|
124
|
+
- lib/metrifox_sdk/client.rb
|
125
|
+
- lib/metrifox_sdk/customers/api.rb
|
126
|
+
- lib/metrifox_sdk/customers/module.rb
|
127
|
+
- lib/metrifox_sdk/types.rb
|
128
|
+
- lib/metrifox_sdk/usages/api.rb
|
129
|
+
- lib/metrifox_sdk/usages/module.rb
|
130
|
+
- lib/metrifox_sdk/util_methods.rb
|
131
|
+
- lib/metrifox_sdk/version.rb
|
132
|
+
homepage: https://github.com/metrifox/metrifox-ruby
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
metadata:
|
136
|
+
homepage_uri: https://github.com/metrifox/metrifox-ruby
|
137
|
+
source_code_uri: https://github.com/metrifox/metrifox-ruby
|
138
|
+
changelog_uri: https://github.com/metrifox/metrifox-ruby/tree/main/CHANGELOG.md
|
139
|
+
post_install_message:
|
140
|
+
rdoc_options: []
|
141
|
+
require_paths:
|
142
|
+
- lib
|
143
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: 2.7.0
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
requirements: []
|
154
|
+
rubygems_version: 3.5.22
|
155
|
+
signing_key:
|
156
|
+
specification_version: 4
|
157
|
+
summary: Ruby SDK for Metrifox API
|
158
|
+
test_files: []
|