bigcommerce-ruby 0.2.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3d1dd058efb06fed8a75053e596034ec4d376c166abbe87bddda3692bdac1d14
4
+ data.tar.gz: 5edcdfa976ffd5abc8da00accab5ca75f4686796ea213a8253f9301fd802460d
5
+ SHA512:
6
+ metadata.gz: 96b0e6f1ba1fc463faf40200f2cc9c9270f22023c9a3600e6a1aed2bb91d6bc4845dc530e7121bcf03bc885359fef02280340641a5aef96b25a6854d1db23a3e
7
+ data.tar.gz: f4323fa4d78e907940e14c651ab56a5ea9083e27e7e7e9491337aefe16dd0269d4d32b57ef3ca8111059318f55eede65d217a6538f50be120dba5edf9eb73f7f
data/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0 (2026-02-24)
4
+
5
+ - Abandoned cart settings resource
6
+ - Abandoned carts resource
7
+ - Inventory adjustments resource
8
+ - Inventory items resource
9
+
10
+ ## 0.1.0 (2026-02-17)
11
+
12
+ - Initial release
13
+ - Orders V2 API support: CRUD, count, archive
14
+ - Order sub-resources: products, shipments, shipping addresses, coupons, taxes, messages, fees, statuses
15
+ - Automatic retry with exponential backoff for rate limits and server errors
16
+ - Typed error classes for all HTTP error codes
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alvaro
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,215 @@
1
+ # bigcommerce-ruby
2
+
3
+ A Ruby gem for the BigCommerce REST Management API. Thin, idiomatic, and built on Faraday — no magic, just clean API access with automatic retries and proper error handling.
4
+
5
+ ## Installation
6
+
7
+ ```ruby
8
+ # Gemfile
9
+ gem "bigcommerce-ruby"
10
+ ```
11
+
12
+ ```
13
+ gem install bigcommerce-ruby
14
+ ```
15
+
16
+ ## Configuration
17
+
18
+ **Global** (recommended for Rails apps):
19
+
20
+ ```ruby
21
+ Bigcommerce.configure do |config|
22
+ config.store_hash = ENV["BIGCOMMERCE_STORE_HASH"]
23
+ config.access_token = ENV["BIGCOMMERCE_ACCESS_TOKEN"]
24
+ config.timeout = 30 # optional, default: 30s
25
+ config.open_timeout = 10 # optional, default: 10s
26
+ end
27
+
28
+ client = Bigcommerce.client
29
+ ```
30
+
31
+ **Per-client** (useful for multi-tenant apps):
32
+
33
+ ```ruby
34
+ client = Bigcommerce::Client.new(
35
+ store_hash: "your_store_hash",
36
+ access_token: "your_access_token"
37
+ )
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ ### Orders
43
+
44
+ ```ruby
45
+ # List with filtering, sorting, and pagination
46
+ client.orders.list(page: 1, limit: 25)
47
+ client.orders.list(status_id: 11, min_date_created: "2025-01-01")
48
+ client.orders.list(sort: "date_created", direction: "desc", customer_id: 42)
49
+
50
+ # Single order
51
+ client.orders.find(100)
52
+
53
+ # Create
54
+ client.orders.create(
55
+ customer_id: 1,
56
+ billing_address: {
57
+ first_name: "John",
58
+ last_name: "Doe",
59
+ street_1: "123 Main St",
60
+ city: "Austin",
61
+ state: "TX",
62
+ zip: "78701",
63
+ country: "United States",
64
+ country_iso2: "US",
65
+ email: "john@example.com"
66
+ },
67
+ products: [
68
+ { product_id: 10, quantity: 2 }
69
+ ]
70
+ )
71
+
72
+ # Update
73
+ client.orders.update(100, status_id: 2, staff_notes: "Shipped today")
74
+
75
+ # Archive
76
+ client.orders.archive(100)
77
+
78
+ # Count
79
+ client.orders.count
80
+ client.orders.count(status_id: 11)
81
+ ```
82
+
83
+ ### Order Products
84
+
85
+ ```ruby
86
+ products = client.order_products(100)
87
+
88
+ products.list
89
+ products.list(page: 1, limit: 10)
90
+ products.find(5)
91
+ ```
92
+
93
+ ### Order Shipments
94
+
95
+ ```ruby
96
+ shipments = client.order_shipments(100)
97
+
98
+ shipments.list
99
+ shipments.find(1)
100
+ shipments.count
101
+
102
+ shipments.create(
103
+ order_address_id: 1,
104
+ items: [{ order_product_id: 10, quantity: 1 }],
105
+ tracking_number: "ABC123",
106
+ shipping_provider: "usps"
107
+ )
108
+
109
+ shipments.update(1, tracking_number: "XYZ789")
110
+ shipments.destroy(1)
111
+ shipments.destroy_all
112
+ ```
113
+
114
+ ### Order Shipping Addresses
115
+
116
+ ```ruby
117
+ addresses = client.order_shipping_addresses(100)
118
+
119
+ addresses.list
120
+ addresses.find(1)
121
+ addresses.update(1, city: "Dallas", state: "TX")
122
+ ```
123
+
124
+ ### Order Coupons
125
+
126
+ ```ruby
127
+ client.order_coupons(100).list
128
+ ```
129
+
130
+ ### Order Taxes
131
+
132
+ ```ruby
133
+ client.order_taxes(100).list
134
+ client.order_taxes(100).list(details: "true")
135
+ ```
136
+
137
+ ### Order Messages
138
+
139
+ ```ruby
140
+ messages = client.order_messages(100)
141
+ messages.list
142
+ messages.list(status: "unread", is_flagged: true)
143
+ ```
144
+
145
+ ### Order Fees
146
+
147
+ ```ruby
148
+ client.order_fees(100).list
149
+ ```
150
+
151
+ ### Order Statuses
152
+
153
+ ```ruby
154
+ client.order_statuses.list
155
+ client.order_statuses.find(1)
156
+ ```
157
+
158
+ ## Response
159
+
160
+ Every method returns a `Bigcommerce::Response`:
161
+
162
+ ```ruby
163
+ response = client.orders.list
164
+
165
+ response.body # Parsed JSON — Hash or Array with symbol keys
166
+ response.status # HTTP status code
167
+ response.headers # Response headers
168
+ response.success? # true for 2xx
169
+ response.rate_limit # Remaining API calls
170
+ response.rate_limit_reset # Time until reset (ms)
171
+ ```
172
+
173
+ ## Error Handling
174
+
175
+ Errors map directly to HTTP status codes:
176
+
177
+ ```ruby
178
+ begin
179
+ client.orders.find(999)
180
+ rescue Bigcommerce::NotFoundError
181
+ puts "Order not found"
182
+ rescue Bigcommerce::AuthenticationError
183
+ puts "Bad credentials — check your access token"
184
+ rescue Bigcommerce::RateLimitError => e
185
+ puts "Rate limited, retry after #{e.response.rate_limit_reset}ms"
186
+ rescue Bigcommerce::UnprocessableEntityError => e
187
+ puts "Validation error: #{e.message}"
188
+ rescue Bigcommerce::ServerError
189
+ puts "BigCommerce server error"
190
+ rescue Bigcommerce::ApiError => e
191
+ puts "API error #{e.status}: #{e.message}"
192
+ end
193
+ ```
194
+
195
+ | Error class | HTTP status |
196
+ |---|---|
197
+ | `AuthenticationError` | 401 |
198
+ | `NotFoundError` | 404 |
199
+ | `UnprocessableEntityError` | 422 |
200
+ | `RateLimitError` | 429 |
201
+ | `ServerError` | 5xx |
202
+ | `ApiError` | anything else |
203
+
204
+ Requests that hit 429 or 5xx are automatically retried up to 3 times with exponential backoff. On a 429, the gem reads the `x-rate-limit-time-reset-ms` header and sleeps accordingly before retrying.
205
+
206
+ ## Development
207
+
208
+ ```
209
+ bundle install
210
+ bundle exec rspec
211
+ ```
212
+
213
+ ## License
214
+
215
+ MIT
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ class Client
5
+ attr_reader :config, :connection
6
+
7
+ def initialize(store_hash: nil, access_token: nil, **options)
8
+ @config = Configuration.new
9
+ @config.store_hash = store_hash || Bigcommerce.configuration.store_hash
10
+ @config.access_token = access_token || Bigcommerce.configuration.access_token
11
+ @config.timeout = options[:timeout] if options[:timeout]
12
+ @config.open_timeout = options[:open_timeout] if options[:open_timeout]
13
+ @config.validate!
14
+ @connection = Connection.new(@config)
15
+ end
16
+
17
+ def orders
18
+ @orders ||= Resources::Orders.new(connection)
19
+ end
20
+
21
+ def order_products(order_id)
22
+ Resources::OrderProducts.new(connection, order_id)
23
+ end
24
+
25
+ def order_shipments(order_id)
26
+ Resources::OrderShipments.new(connection, order_id)
27
+ end
28
+
29
+ def order_shipping_addresses(order_id)
30
+ Resources::OrderShippingAddresses.new(connection, order_id)
31
+ end
32
+
33
+ def order_coupons(order_id)
34
+ Resources::OrderCoupons.new(connection, order_id)
35
+ end
36
+
37
+ def order_taxes(order_id)
38
+ Resources::OrderTaxes.new(connection, order_id)
39
+ end
40
+
41
+ def order_messages(order_id)
42
+ Resources::OrderMessages.new(connection, order_id)
43
+ end
44
+
45
+ def order_fees(order_id)
46
+ Resources::OrderFees.new(connection, order_id)
47
+ end
48
+
49
+ def order_statuses
50
+ @order_statuses ||= Resources::OrderStatuses.new(connection)
51
+ end
52
+
53
+ def abandoned_carts
54
+ @abandoned_carts ||= Resources::AbandonedCarts.new(connection)
55
+ end
56
+
57
+ def abandoned_cart_settings
58
+ @abandoned_cart_settings ||= Resources::AbandonedCartSettings.new(connection)
59
+ end
60
+
61
+ def inventory_items
62
+ @inventory_items ||= Resources::InventoryItems.new(connection)
63
+ end
64
+
65
+ def inventory_adjustments
66
+ @inventory_adjustments ||= Resources::InventoryAdjustments.new(connection)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ class Configuration
5
+ attr_accessor :store_hash, :access_token, :timeout, :open_timeout
6
+
7
+ def initialize
8
+ @store_hash = nil
9
+ @access_token = nil
10
+ @timeout = 30
11
+ @open_timeout = 10
12
+ end
13
+
14
+ def validate!
15
+ raise ConfigurationError, "store_hash is required" if store_hash.nil? || store_hash.empty?
16
+ raise ConfigurationError, "access_token is required" if access_token.nil? || access_token.empty?
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "faraday/retry"
5
+ require "json"
6
+
7
+ module Bigcommerce
8
+ class Connection
9
+ BASE_URL = "https://api.bigcommerce.com/stores"
10
+
11
+ def initialize(config)
12
+ @config = config
13
+ end
14
+
15
+ def get(path, params = {}, api_version: :v2)
16
+ request(:get, path, params, api_version: api_version)
17
+ end
18
+
19
+ def post(path, body = {}, api_version: :v2)
20
+ request(:post, path, body, api_version: api_version)
21
+ end
22
+
23
+ def put(path, body = {}, api_version: :v2)
24
+ request(:put, path, body, api_version: api_version)
25
+ end
26
+
27
+ def delete(path, params = {}, api_version: :v2)
28
+ request(:delete, path, params, api_version: api_version)
29
+ end
30
+
31
+ private
32
+
33
+ def request(method, path, payload = {}, api_version: :v2)
34
+ response = connection.run_request(method, "#{base_url(api_version)}#{path}", nil, nil) do |req|
35
+ case method
36
+ when :get, :delete
37
+ req.params = payload if payload.any?
38
+ when :post, :put
39
+ req.body = JSON.generate(payload)
40
+ end
41
+ end
42
+
43
+ handle_response(response)
44
+ end
45
+
46
+ def connection
47
+ @connection ||= Faraday.new do |f|
48
+ f.request :retry, max: 3, interval: 0.5, backoff_factor: 2,
49
+ retry_statuses: [429, 500, 502, 503, 504],
50
+ retry_block: ->(env:, options:, retry_count:, exception:, will_retry_in:) {
51
+ handle_rate_limit(env) if env&.status == 429
52
+ }
53
+ f.headers["X-Auth-Token"] = @config.access_token
54
+ f.headers["Content-Type"] = "application/json"
55
+ f.headers["Accept"] = "application/json"
56
+ f.options.timeout = @config.timeout
57
+ f.options.open_timeout = @config.open_timeout
58
+ end
59
+ end
60
+
61
+ def base_url(api_version = :v2)
62
+ "#{BASE_URL}/#{@config.store_hash}/#{api_version}"
63
+ end
64
+
65
+ def handle_response(faraday_response)
66
+ response = Response.new(faraday_response)
67
+
68
+ case faraday_response.status
69
+ when 200..299
70
+ response
71
+ when 401
72
+ raise AuthenticationError.new("Invalid credentials", response: response)
73
+ when 404
74
+ raise NotFoundError.new("Resource not found", response: response)
75
+ when 422
76
+ raise UnprocessableEntityError.new(error_message(response), response: response)
77
+ when 429
78
+ raise RateLimitError.new("Rate limit exceeded", response: response)
79
+ when 500..599
80
+ raise ServerError.new("Server error", response: response)
81
+ else
82
+ raise ApiError.new(
83
+ error_message(response),
84
+ status: faraday_response.status,
85
+ body: response.body,
86
+ response: response
87
+ )
88
+ end
89
+ end
90
+
91
+ def error_message(response)
92
+ return "Unknown error" unless response.body.is_a?(Hash)
93
+
94
+ response.body[:title] || response.body[:message] || response.body.to_s
95
+ end
96
+
97
+ def handle_rate_limit(env)
98
+ reset_ms = env.response_headers&.dig("x-rate-limit-time-reset-ms")
99
+ sleep(reset_ms.to_f / 1000) if reset_ms
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ class Error < StandardError
5
+ attr_reader :response
6
+
7
+ def initialize(message = nil, response: nil)
8
+ @response = response
9
+ super(message)
10
+ end
11
+ end
12
+
13
+ class ConfigurationError < Error; end
14
+ class AuthenticationError < Error; end
15
+ class NotFoundError < Error; end
16
+ class RateLimitError < Error; end
17
+ class UnprocessableEntityError < Error; end
18
+ class ServerError < Error; end
19
+
20
+ class ApiError < Error
21
+ attr_reader :status, :body
22
+
23
+ def initialize(message = nil, status: nil, body: nil, response: nil)
24
+ @status = status
25
+ @body = body
26
+ super(message, response: response)
27
+ end
28
+
29
+ def to_s
30
+ "#{status}: #{message}"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ class Resource
5
+ attr_reader :connection
6
+
7
+ def initialize(connection)
8
+ @connection = connection
9
+ end
10
+
11
+ private
12
+
13
+ def api_version
14
+ :v2
15
+ end
16
+
17
+ def get(path, params = {})
18
+ connection.get(path, params, api_version: api_version)
19
+ end
20
+
21
+ def post(path, body = {})
22
+ connection.post(path, body, api_version: api_version)
23
+ end
24
+
25
+ def put(path, body = {})
26
+ connection.put(path, body, api_version: api_version)
27
+ end
28
+
29
+ def delete(path, params = {})
30
+ connection.delete(path, params, api_version: api_version)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class AbandonedCartSettings < Resource
6
+ # GET /abandoned-carts/settings
7
+ # Get global abandoned cart settings.
8
+ # @return [Bigcommerce::Response]
9
+ def get_global
10
+ get("/abandoned-carts/settings")
11
+ end
12
+
13
+ # PUT /abandoned-carts/settings
14
+ # Update global abandoned cart settings.
15
+ # @param attributes [Hash] Settings attributes
16
+ # @option attributes [Boolean] :enable_notification Enable abandoned cart notifications
17
+ # @option attributes [Boolean] :email_customer_until_cart_is_recovered Email customer until cart is recovered
18
+ # @option attributes [Boolean] :marketing_emails_require_customer_consent Require customer consent for marketing emails
19
+ # @option attributes [Boolean] :email_merchant_when_cart_is_converted Email merchant when cart is converted
20
+ # @option attributes [Boolean] :email_merchant_when_cart_is_abandoned Email merchant when cart is abandoned
21
+ # @option attributes [String] :merchant_email_address Merchant email address
22
+ # @option attributes [String] :merchant_abandoned_cart_email_frequency_type Frequency type ("digest" or "individual")
23
+ # @option attributes [Integer] :merchant_abandoned_cart_digest_email_frequency Digest frequency (2-1000)
24
+ # @return [Bigcommerce::Response]
25
+ def update_global(**attributes)
26
+ put("/abandoned-carts/settings", attributes)
27
+ end
28
+
29
+ # GET /abandoned-carts/settings/channels/:channel_id
30
+ # Get channel-specific abandoned cart settings.
31
+ # @param channel_id [Integer] Channel ID
32
+ # @return [Bigcommerce::Response]
33
+ def get_channel(channel_id)
34
+ get("/abandoned-carts/settings/channels/#{channel_id}")
35
+ end
36
+
37
+ # PUT /abandoned-carts/settings/channels/:channel_id
38
+ # Update channel-specific abandoned cart settings.
39
+ # All fields are nullable — set to nil to inherit from global settings.
40
+ # @param channel_id [Integer] Channel ID
41
+ # @param attributes [Hash] Settings attributes (same as global, but all nullable)
42
+ # @return [Bigcommerce::Response]
43
+ def update_channel(channel_id, **attributes)
44
+ put("/abandoned-carts/settings/channels/#{channel_id}", attributes)
45
+ end
46
+
47
+ private
48
+
49
+ def api_version
50
+ :v3
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class AbandonedCarts < Resource
6
+ # GET /abandoned-carts/:token
7
+ # Returns the cart_id for a given abandoned cart token.
8
+ # The token is the UUID found in the query string of abandoned cart email links.
9
+ # @param token [String] Abandoned cart UUID token
10
+ # @return [Bigcommerce::Response]
11
+ def find(token)
12
+ get("/abandoned-carts/#{token}")
13
+ end
14
+
15
+ private
16
+
17
+ def api_version
18
+ :v3
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class InventoryAdjustments < Resource
6
+ # PUT /inventory/adjustments/absolute
7
+ # Set inventory to an absolute quantity. Identifies items by location_id and
8
+ # one of: sku, variant_id, or product_id.
9
+ # @param items [Array<Hash>] Array of adjustment items
10
+ # Each hash must include :location_id, :quantity, and one of :sku, :variant_id, or :product_id
11
+ # @param reason [String] Optional reason for the adjustment
12
+ # @return [Bigcommerce::Response]
13
+ def absolute(items:, reason: nil)
14
+ body = { items: items }
15
+ body[:reason] = reason if reason
16
+ put("/inventory/adjustments/absolute", body)
17
+ end
18
+
19
+ # POST /inventory/adjustments/relative
20
+ # Adjust inventory by a relative quantity (positive to add, negative to subtract).
21
+ # Identifies items by location_id and one of: sku, variant_id, or product_id.
22
+ # @param items [Array<Hash>] Array of adjustment items
23
+ # Each hash must include :location_id, :quantity, and one of :sku, :variant_id, or :product_id
24
+ # @param reason [String] Optional reason for the adjustment
25
+ # @return [Bigcommerce::Response]
26
+ def relative(items:, reason: nil)
27
+ body = { items: items }
28
+ body[:reason] = reason if reason
29
+ post("/inventory/adjustments/relative", body)
30
+ end
31
+
32
+ private
33
+
34
+ def api_version
35
+ :v3
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class InventoryItems < Resource
6
+ # GET /inventory/items
7
+ # Get inventory at all locations.
8
+ # @param params [Hash] Query parameters
9
+ # @option params [String] :"sku:in" Comma-separated SKUs
10
+ # @option params [String] :"variant_id:in" Comma-separated variant IDs
11
+ # @option params [String] :"product_id:in" Comma-separated product IDs
12
+ # @option params [String] :"location_id:in" Comma-separated location IDs
13
+ # @option params [String] :"location_code:in" Comma-separated location codes
14
+ # @option params [Integer] :page Page number
15
+ # @option params [Integer] :limit Items per page
16
+ # @return [Bigcommerce::Response]
17
+ def list(**params)
18
+ get("/inventory/items", params)
19
+ end
20
+
21
+ # GET /inventory/locations/:location_id/items
22
+ # Get inventory at a specific location.
23
+ # @param location_id [Integer] Location ID
24
+ # @param params [Hash] Query parameters
25
+ # @option params [String] :"sku:in" Comma-separated SKUs
26
+ # @option params [String] :"variant_id:in" Comma-separated variant IDs
27
+ # @option params [String] :"product_id:in" Comma-separated product IDs
28
+ # @option params [Integer] :page Page number
29
+ # @option params [Integer] :limit Items per page
30
+ # @return [Bigcommerce::Response]
31
+ def list_for_location(location_id, **params)
32
+ get("/inventory/locations/#{location_id}/items", params)
33
+ end
34
+
35
+ # PUT /inventory/locations/:location_id/items
36
+ # Update inventory settings (safety_stock, is_in_stock, warning_level, bin_picking_number)
37
+ # for items at a specific location.
38
+ # @param location_id [Integer] Location ID
39
+ # @param settings [Array<Hash>] Array of setting objects
40
+ # Each hash must include :identity (with :sku, :variant_id, or :product_id)
41
+ # and at least one of: :safety_stock, :is_in_stock, :warning_level, :bin_picking_number
42
+ # @return [Bigcommerce::Response]
43
+ def update_settings(location_id, settings:)
44
+ put("/inventory/locations/#{location_id}/items", { settings: settings })
45
+ end
46
+
47
+ private
48
+
49
+ def api_version
50
+ :v3
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class OrderCoupons < Resource
6
+ def initialize(connection, order_id)
7
+ super(connection)
8
+ @order_id = order_id
9
+ end
10
+
11
+ # GET /orders/:order_id/coupons
12
+ # @param params [Hash] Query parameters
13
+ # @option params [Integer] :page Page number (default: 1)
14
+ # @option params [Integer] :limit Results per page (default: 50)
15
+ # @return [Bigcommerce::Response]
16
+ def list(**params)
17
+ get("/orders/#{@order_id}/coupons", params)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class OrderFees < Resource
6
+ def initialize(connection, order_id)
7
+ super(connection)
8
+ @order_id = order_id
9
+ end
10
+
11
+ # GET /orders/:order_id/fees
12
+ # @param id [Integer] Order ID
13
+ # @return [Bigcommerce::Response]
14
+ def list
15
+ get("/orders/#{@order_id}/fees")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class OrderMessages < Resource
6
+ def initialize(connection, order_id)
7
+ super(connection)
8
+ @order_id = order_id
9
+ end
10
+
11
+ # GET /orders/:order_id/messages
12
+ # @param params [Hash] Query parameters
13
+ # @option params [Integer] :min_id Minimum message ID
14
+ # @option params [Integer] :max_id Maximum message ID
15
+ # @option params [Integer] :customer_id Filter by customer ID
16
+ # @option params [String] :min_date_created Minimum date created
17
+ # @option params [String] :max_date_created Maximum date created
18
+ # @option params [Boolean] :is_flagged Filter by flagged status
19
+ # @option params [String] :status Filter by status (read, unread)
20
+ # @option params [Integer] :page Page number (default: 1)
21
+ # @option params [Integer] :limit Results per page (default: 50)
22
+ # @return [Bigcommerce::Response]
23
+ def list(**params)
24
+ get("/orders/#{@order_id}/messages", params)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class OrderProducts < Resource
6
+ def initialize(connection, order_id)
7
+ super(connection)
8
+ @order_id = order_id
9
+ end
10
+
11
+ # GET /orders/:order_id/products
12
+ # @param params [Hash] Query parameters
13
+ # @option params [Integer] :page Page number (default: 1)
14
+ # @option params [Integer] :limit Results per page (default: 50)
15
+ # @return [Bigcommerce::Response]
16
+ def list(**params)
17
+ get("/orders/#{@order_id}/products", params)
18
+ end
19
+
20
+ # GET /orders/:order_id/products/:id
21
+ # @param id [Integer] Order product ID
22
+ # @return [Bigcommerce::Response]
23
+ def find(id)
24
+ get("/orders/#{@order_id}/products/#{id}")
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class OrderShipments < Resource
6
+ def initialize(connection, order_id)
7
+ super(connection)
8
+ @order_id = order_id
9
+ end
10
+
11
+ # GET /orders/:order_id/shipments
12
+ # @param params [Hash] Query parameters
13
+ # @option params [Integer] :page Page number (default: 1)
14
+ # @option params [Integer] :limit Results per page (default: 50)
15
+ # @return [Bigcommerce::Response]
16
+ def list(**params)
17
+ get("/orders/#{@order_id}/shipments", params)
18
+ end
19
+
20
+ # GET /orders/:order_id/shipments/:id
21
+ # @param id [Integer] Shipment ID
22
+ # @return [Bigcommerce::Response]
23
+ def find(id)
24
+ get("/orders/#{@order_id}/shipments/#{id}")
25
+ end
26
+
27
+ # POST /orders/:order_id/shipments
28
+ # @param attributes [Hash] Shipment attributes
29
+ # @option attributes [Integer] :order_address_id Required - shipping address ID
30
+ # @option attributes [Array<Hash>] :items Required - [{order_product_id:, quantity:}]
31
+ # @option attributes [String] :tracking_number Tracking number
32
+ # @option attributes [String] :shipping_provider Shipping provider name
33
+ # @option attributes [String] :tracking_carrier Tracking carrier
34
+ # @option attributes [String] :tracking_link Tracking URL
35
+ # @option attributes [String] :merchant_shipping_cost Shipping cost (decimal string)
36
+ # @return [Bigcommerce::Response]
37
+ def create(**attributes)
38
+ post("/orders/#{@order_id}/shipments", attributes)
39
+ end
40
+
41
+ # PUT /orders/:order_id/shipments/:id
42
+ # @param id [Integer] Shipment ID
43
+ # @param attributes [Hash] Shipment attributes to update
44
+ # @return [Bigcommerce::Response]
45
+ def update(id, **attributes)
46
+ put("/orders/#{@order_id}/shipments/#{id}", attributes)
47
+ end
48
+
49
+ # DELETE /orders/:order_id/shipments/:id
50
+ # @param id [Integer] Shipment ID
51
+ # @return [Bigcommerce::Response]
52
+ def destroy(id)
53
+ delete("/orders/#{@order_id}/shipments/#{id}")
54
+ end
55
+
56
+ # DELETE /orders/:order_id/shipments
57
+ # Deletes all shipments for the order
58
+ # @return [Bigcommerce::Response]
59
+ def destroy_all
60
+ delete("/orders/#{@order_id}/shipments")
61
+ end
62
+
63
+ # GET /orders/:order_id/shipments/count
64
+ # @return [Bigcommerce::Response]
65
+ def count
66
+ get("/orders/#{@order_id}/shipments/count")
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class OrderShippingAddresses < Resource
6
+ def initialize(connection, order_id)
7
+ super(connection)
8
+ @order_id = order_id
9
+ end
10
+
11
+ # GET /orders/:order_id/shipping_addresses
12
+ # @param params [Hash] Query parameters
13
+ # @option params [Integer] :page Page number (default: 1)
14
+ # @option params [Integer] :limit Results per page (default: 50)
15
+ # @return [Bigcommerce::Response]
16
+ def list(**params)
17
+ get("/orders/#{@order_id}/shipping_addresses", params)
18
+ end
19
+
20
+ # GET /orders/:order_id/shipping_addresses/:id
21
+ # @param id [Integer] Shipping address ID
22
+ # @return [Bigcommerce::Response]
23
+ def find(id)
24
+ get("/orders/#{@order_id}/shipping_addresses/#{id}")
25
+ end
26
+
27
+ # PUT /orders/:order_id/shipping_addresses/:id
28
+ # @param id [Integer] Shipping address ID
29
+ # @param attributes [Hash] Address attributes to update
30
+ # @return [Bigcommerce::Response]
31
+ def update(id, **attributes)
32
+ put("/orders/#{@order_id}/shipping_addresses/#{id}", attributes)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class OrderStatuses < Resource
6
+ # GET /order_statuses
7
+ # @return [Bigcommerce::Response]
8
+ def list
9
+ get("/order_statuses")
10
+ end
11
+
12
+ # GET /order_statuses/:id
13
+ # @param id [Integer] Status ID
14
+ # @return [Bigcommerce::Response]
15
+ def find(id)
16
+ get("/order_statuses/#{id}")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class OrderTaxes < Resource
6
+ def initialize(connection, order_id)
7
+ super(connection)
8
+ @order_id = order_id
9
+ end
10
+
11
+ # GET /orders/:order_id/taxes
12
+ # @param params [Hash] Query parameters
13
+ # @option params [Integer] :page Page number (default: 1)
14
+ # @option params [Integer] :limit Results per page (default: 50)
15
+ # @option params [String] :details Include tax details ('true' or 'false')
16
+ # @return [Bigcommerce::Response]
17
+ def list(**params)
18
+ get("/orders/#{@order_id}/taxes", params)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ module Resources
5
+ class Orders < Resource
6
+ # GET /orders
7
+ # @param params [Hash] Query parameters
8
+ # @option params [Integer] :min_id Minimum order ID
9
+ # @option params [Integer] :max_id Maximum order ID
10
+ # @option params [Float] :min_total Minimum order total
11
+ # @option params [Float] :max_total Maximum order total
12
+ # @option params [Integer] :customer_id Filter by customer ID
13
+ # @option params [String] :email Filter by customer email
14
+ # @option params [Integer] :status_id Filter by status ID
15
+ # @option params [String] :cart_id Filter by cart ID
16
+ # @option params [String] :payment_method Filter by payment method
17
+ # @option params [String] :min_date_created Minimum date created (RFC-2822 or ISO-8601)
18
+ # @option params [String] :max_date_created Maximum date created
19
+ # @option params [String] :min_date_modified Minimum date modified
20
+ # @option params [String] :max_date_modified Maximum date modified
21
+ # @option params [Integer] :page Page number (default: 1)
22
+ # @option params [Integer] :limit Results per page (default: 50)
23
+ # @option params [String] :sort Sort field (id, customer_id, date_created, date_modified, status_id, channel_id, external_id)
24
+ # @option params [Integer] :channel_id Filter by channel ID
25
+ # @option params [String] :external_order_id Filter by external order ID
26
+ # @option params [Array<String>] :include Side-load resources (consignments, consignments.line_items, fees)
27
+ # @return [Bigcommerce::Response]
28
+ def list(**params)
29
+ get("/orders", params)
30
+ end
31
+
32
+ # GET /orders/:id
33
+ # @param id [Integer] Order ID
34
+ # @param params [Hash] Query parameters
35
+ # @option params [Array<String>] :include Side-load resources
36
+ # @return [Bigcommerce::Response]
37
+ def find(id, **params)
38
+ get("/orders/#{id}", params)
39
+ end
40
+
41
+ # POST /orders
42
+ # @param attributes [Hash] Order attributes
43
+ # @return [Bigcommerce::Response]
44
+ def create(**attributes)
45
+ post("/orders", attributes)
46
+ end
47
+
48
+ # PUT /orders/:id
49
+ # @param id [Integer] Order ID
50
+ # @param attributes [Hash] Order attributes to update
51
+ # @return [Bigcommerce::Response]
52
+ def update(id, **attributes)
53
+ put("/orders/#{id}", attributes)
54
+ end
55
+
56
+ # DELETE /orders/:id
57
+ # Archives an order
58
+ # @param id [Integer] Order ID
59
+ # @return [Bigcommerce::Response]
60
+ def archive(id)
61
+ delete("/orders/#{id}")
62
+ end
63
+
64
+ # DELETE /orders
65
+ # Archives all orders (use with caution)
66
+ # @return [Bigcommerce::Response]
67
+ def archive_all
68
+ delete("/orders")
69
+ end
70
+
71
+ # GET /orders/count
72
+ # @param params [Hash] Same filter params as #list (except page/limit/sort/include)
73
+ # @return [Bigcommerce::Response]
74
+ def count(**params)
75
+ get("/orders/count", params)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ class Response
5
+ attr_reader :status, :headers, :body
6
+
7
+ def initialize(faraday_response)
8
+ @status = faraday_response.status
9
+ @headers = faraday_response.headers
10
+ @body = parse_body(faraday_response.body)
11
+ end
12
+
13
+ def success?
14
+ (200..299).cover?(status)
15
+ end
16
+
17
+ def rate_limit
18
+ headers["x-rate-limit-requests-left"]&.to_i
19
+ end
20
+
21
+ def rate_limit_reset
22
+ headers["x-rate-limit-time-reset-ms"]&.to_i
23
+ end
24
+
25
+ private
26
+
27
+ def parse_body(raw)
28
+ return nil if raw.nil? || raw.empty?
29
+
30
+ JSON.parse(raw, symbolize_names: true)
31
+ rescue JSON::ParserError
32
+ raw
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bigcommerce
4
+ VERSION = "0.2.0"
5
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "bigcommerce/version"
4
+ require_relative "bigcommerce/configuration"
5
+ require_relative "bigcommerce/errors"
6
+ require_relative "bigcommerce/response"
7
+ require_relative "bigcommerce/connection"
8
+ require_relative "bigcommerce/resource"
9
+ require_relative "bigcommerce/client"
10
+ require_relative "bigcommerce/resources/orders"
11
+ require_relative "bigcommerce/resources/order_products"
12
+ require_relative "bigcommerce/resources/order_shipments"
13
+ require_relative "bigcommerce/resources/order_shipping_addresses"
14
+ require_relative "bigcommerce/resources/order_coupons"
15
+ require_relative "bigcommerce/resources/order_taxes"
16
+ require_relative "bigcommerce/resources/order_messages"
17
+ require_relative "bigcommerce/resources/order_fees"
18
+ require_relative "bigcommerce/resources/order_statuses"
19
+ require_relative "bigcommerce/resources/abandoned_carts"
20
+ require_relative "bigcommerce/resources/abandoned_cart_settings"
21
+ require_relative "bigcommerce/resources/inventory_items"
22
+ require_relative "bigcommerce/resources/inventory_adjustments"
23
+
24
+ module Bigcommerce
25
+ class << self
26
+ attr_writer :configuration
27
+
28
+ def configuration
29
+ @configuration ||= Configuration.new
30
+ end
31
+
32
+ def configure
33
+ yield(configuration)
34
+ end
35
+
36
+ def client(**options)
37
+ Client.new(**options)
38
+ end
39
+
40
+ def reset!
41
+ @configuration = Configuration.new
42
+ end
43
+ end
44
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bigcommerce-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Alvaro
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: faraday
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: faraday-retry
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ description: A lightweight Ruby wrapper for the BigCommerce V2 Orders API with support
41
+ for orders, shipments, products, and more.
42
+ email:
43
+ - aalvaaro@users.noreply.github.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - CHANGELOG.md
49
+ - LICENSE
50
+ - README.md
51
+ - lib/bigcommerce.rb
52
+ - lib/bigcommerce/client.rb
53
+ - lib/bigcommerce/configuration.rb
54
+ - lib/bigcommerce/connection.rb
55
+ - lib/bigcommerce/errors.rb
56
+ - lib/bigcommerce/resource.rb
57
+ - lib/bigcommerce/resources/abandoned_cart_settings.rb
58
+ - lib/bigcommerce/resources/abandoned_carts.rb
59
+ - lib/bigcommerce/resources/inventory_adjustments.rb
60
+ - lib/bigcommerce/resources/inventory_items.rb
61
+ - lib/bigcommerce/resources/order_coupons.rb
62
+ - lib/bigcommerce/resources/order_fees.rb
63
+ - lib/bigcommerce/resources/order_messages.rb
64
+ - lib/bigcommerce/resources/order_products.rb
65
+ - lib/bigcommerce/resources/order_shipments.rb
66
+ - lib/bigcommerce/resources/order_shipping_addresses.rb
67
+ - lib/bigcommerce/resources/order_statuses.rb
68
+ - lib/bigcommerce/resources/order_taxes.rb
69
+ - lib/bigcommerce/resources/orders.rb
70
+ - lib/bigcommerce/response.rb
71
+ - lib/bigcommerce/version.rb
72
+ homepage: https://github.com/AAlvAAro/bigcommerce-ruby
73
+ licenses:
74
+ - MIT
75
+ metadata:
76
+ homepage_uri: https://github.com/AAlvAAro/bigcommerce-ruby
77
+ source_code_uri: https://github.com/AAlvAAro/bigcommerce-ruby
78
+ changelog_uri: https://github.com/AAlvAAro/bigcommerce-ruby/blob/main/CHANGELOG.md
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '3.1'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubygems_version: 3.6.9
94
+ specification_version: 4
95
+ summary: Ruby client for the BigCommerce REST Management API
96
+ test_files: []