shopify_api 4.9.0 → 5.0.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 +4 -4
- data/.rubocop.yml +8 -0
- data/.travis.yml +0 -4
- data/CHANGELOG +25 -0
- data/README.md +36 -14
- data/lib/shopify_api/limits.rb +1 -2
- data/lib/shopify_api/resources/abandoned_checkout.rb +7 -0
- data/lib/shopify_api/resources/access_scope.rb +5 -0
- data/lib/shopify_api/resources/api_permission.rb +9 -0
- data/lib/shopify_api/resources/asset.rb +8 -8
- data/lib/shopify_api/resources/billing_address.rb +1 -1
- data/lib/shopify_api/resources/checkout.rb +24 -1
- data/lib/shopify_api/resources/custom_collection.rb +3 -3
- data/lib/shopify_api/resources/{customer_invite_message.rb → customer_invite.rb} +0 -0
- data/lib/shopify_api/resources/graphql.rb +22 -0
- data/lib/shopify_api/resources/image.rb +2 -2
- data/lib/shopify_api/resources/inventory_item.rb +6 -0
- data/lib/shopify_api/resources/inventory_level.rb +55 -0
- data/lib/shopify_api/resources/line_item.rb +9 -1
- data/lib/shopify_api/resources/location.rb +4 -0
- data/lib/shopify_api/resources/o_auth.rb +8 -0
- data/lib/shopify_api/resources/order.rb +7 -2
- data/lib/shopify_api/resources/payment.rb +7 -0
- data/lib/shopify_api/resources/ping.rb +3 -0
- data/lib/shopify_api/resources/ping/conversation.rb +18 -0
- data/lib/shopify_api/resources/ping/message.rb +9 -0
- data/lib/shopify_api/resources/product.rb +4 -4
- data/lib/shopify_api/resources/shipping_line.rb +1 -1
- data/lib/shopify_api/resources/shipping_rate.rb +7 -0
- data/lib/shopify_api/resources/shop.rb +4 -4
- data/lib/shopify_api/session.rb +1 -1
- data/lib/shopify_api/version.rb +1 -1
- data/shopify_api.gemspec +2 -1
- data/test/abandoned_checkouts_test.rb +29 -0
- data/test/api_permission_test.rb +9 -0
- data/test/checkouts_test.rb +67 -4
- data/test/detailed_log_subscriber_test.rb +3 -2
- data/test/fixtures/abandoned_checkout.json +184 -0
- data/test/fixtures/abandoned_checkouts.json +186 -0
- data/test/fixtures/checkout.json +160 -0
- data/test/fixtures/checkouts.json +25 -49
- data/test/fixtures/inventory_level.json +7 -0
- data/test/fixtures/inventory_levels.json +24 -0
- data/test/fixtures/order_with_properties.json +373 -0
- data/test/fixtures/payment.json +7 -0
- data/test/fixtures/payments.json +9 -0
- data/test/fixtures/ping/conversation.json +1 -0
- data/test/fixtures/ping/message.json +1 -0
- data/test/fixtures/shipping_rates.json +12 -0
- data/test/inventory_level_test.rb +59 -0
- data/test/location_test.rb +14 -0
- data/test/order_test.rb +13 -1
- data/test/payment_test.rb +19 -0
- data/test/ping/conversation_test.rb +39 -0
- data/test/session_test.rb +11 -11
- data/test/shipping_rate_test.rb +17 -0
- data/test/test_helper.rb +7 -5
- data/test/variant_test.rb +4 -1
- metadata +49 -10
- data/lib/shopify_api/resources/discount.rb +0 -11
- data/test/discount_test.rb +0 -52
- data/test/fixtures/discount.json +0 -17
- data/test/fixtures/discount_disabled.json +0 -17
- data/test/fixtures/discounts.json +0 -34
@@ -3,8 +3,13 @@ module ShopifyAPI
|
|
3
3
|
include Events
|
4
4
|
include Metafields
|
5
5
|
|
6
|
-
def close
|
7
|
-
|
6
|
+
def close
|
7
|
+
load_attributes_from_response(post(:close, {}, only_id))
|
8
|
+
end
|
9
|
+
|
10
|
+
def open
|
11
|
+
load_attributes_from_response(post(:open, {}, only_id))
|
12
|
+
end
|
8
13
|
|
9
14
|
def cancel(options = {})
|
10
15
|
load_attributes_from_response(post(:cancel, {}, options.to_json))
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShopifyAPI
|
4
|
+
module Ping
|
5
|
+
class Conversation < Base
|
6
|
+
self.prefix = "/admin/api/ping-api/v1/"
|
7
|
+
|
8
|
+
def send_message(message_attrs)
|
9
|
+
message = ShopifyAPI::Ping::Message.new(
|
10
|
+
message_attrs.merge(conversation_id: id)
|
11
|
+
)
|
12
|
+
|
13
|
+
message.save
|
14
|
+
message
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -13,19 +13,19 @@ module ShopifyAPI
|
|
13
13
|
format % prices.min
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def collections
|
18
18
|
CustomCollection.find(:all, :params => {:product_id => self.id})
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
def smart_collections
|
22
22
|
SmartCollection.find(:all, :params => {:product_id => self.id})
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def add_to_collection(collection)
|
26
26
|
collection.add_product(self)
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def remove_from_collection(collection)
|
30
30
|
collection.remove_product(self)
|
31
31
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module ShopifyAPI
|
2
|
-
# Shop object. Use Shop.current to receive
|
2
|
+
# Shop object. Use Shop.current to receive
|
3
3
|
# the shop.
|
4
4
|
class Shop < Base
|
5
5
|
def self.current(options={})
|
@@ -11,13 +11,13 @@ module ShopifyAPI
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def add_metafield(metafield)
|
14
|
-
raise ArgumentError, "You can only add metafields to resource that has been saved" if new?
|
14
|
+
raise ArgumentError, "You can only add metafields to resource that has been saved" if new?
|
15
15
|
metafield.save
|
16
16
|
metafield
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def events
|
20
20
|
Event.find(:all)
|
21
21
|
end
|
22
|
-
end
|
22
|
+
end
|
23
23
|
end
|
data/lib/shopify_api/session.rb
CHANGED
@@ -51,7 +51,7 @@ module ShopifyAPI
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def validate_signature(params)
|
54
|
-
params = params.with_indifferent_access
|
54
|
+
params = (params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params).with_indifferent_access
|
55
55
|
return false unless signature = params[:hmac]
|
56
56
|
|
57
57
|
calculated_signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new(), secret, encoded_params_for_signature(params))
|
data/lib/shopify_api/version.rb
CHANGED
data/shopify_api.gemspec
CHANGED
@@ -23,10 +23,11 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.summary = %q{ShopifyAPI is a lightweight gem for accessing the Shopify admin REST web services}
|
24
24
|
s.license = "MIT"
|
25
25
|
|
26
|
-
s.required_ruby_version = ">= 2.
|
26
|
+
s.required_ruby_version = ">= 2.1"
|
27
27
|
|
28
28
|
s.add_runtime_dependency("activeresource", ">= 3.0.0")
|
29
29
|
s.add_runtime_dependency("rack")
|
30
|
+
s.add_runtime_dependency("graphql-client")
|
30
31
|
|
31
32
|
s.add_development_dependency("mocha", ">= 0.9.8")
|
32
33
|
s.add_development_dependency("fakeweb")
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class AbandonedCheckoutsTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
super
|
7
|
+
|
8
|
+
@expected_checkouts = JSON.parse(load_fixture('abandoned_checkouts'))['checkouts']
|
9
|
+
@expected_checkout_id = JSON.parse(load_fixture('abandoned_checkout'))['checkout']['id']
|
10
|
+
end
|
11
|
+
|
12
|
+
test ":create creates a checkout" do
|
13
|
+
fake 'checkouts', method: :post, status: 201, body: load_fixture('abandoned_checkout')
|
14
|
+
|
15
|
+
checkout = ShopifyAPI::AbandonedCheckout.create
|
16
|
+
|
17
|
+
assert_equal @expected_checkout_id, checkout.id
|
18
|
+
assert_equal true, checkout.attributes.include?(:abandoned_checkout_url)
|
19
|
+
end
|
20
|
+
|
21
|
+
test "get all checkouts indexed by token" do
|
22
|
+
fake 'checkouts', method: :get, status: 200, body: load_fixture('abandoned_checkouts')
|
23
|
+
|
24
|
+
checkouts = ShopifyAPI::AbandonedCheckout.all
|
25
|
+
|
26
|
+
assert_equal @expected_checkout_id, checkouts.first.id
|
27
|
+
assert_equal @expected_checkouts.size, checkouts.size
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class ApiPermissionTest < Test::Unit::TestCase
|
5
|
+
test "revoke access token" do
|
6
|
+
fake "api_permissions/current", method: :delete, status: 200, body: "{}"
|
7
|
+
assert ShopifyAPI::ApiPermission.destroy
|
8
|
+
end
|
9
|
+
end
|
data/test/checkouts_test.rb
CHANGED
@@ -1,9 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'test_helper'
|
2
3
|
|
3
4
|
class CheckoutsTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
def setup
|
6
|
+
super
|
7
|
+
|
8
|
+
@expected_checkouts = JSON.parse(load_fixture('checkouts'))['checkouts']
|
9
|
+
@expected_checkout_id = JSON.parse(load_fixture('checkout'))['checkout']['token']
|
10
|
+
end
|
11
|
+
|
12
|
+
test ":create creates a checkout" do
|
13
|
+
fake 'checkouts', method: :post, status: 201, body: load_fixture('checkout')
|
14
|
+
|
15
|
+
checkout = ShopifyAPI::Checkout.create
|
16
|
+
|
17
|
+
assert_equal @expected_checkout_id, checkout.id
|
18
|
+
end
|
19
|
+
|
20
|
+
test "get all checkouts indexed by token" do
|
21
|
+
fake 'checkouts', method: :get, status: 200, body: load_fixture('checkouts')
|
22
|
+
|
23
|
+
checkouts = ShopifyAPI::Checkout.all
|
24
|
+
|
25
|
+
assert_equal @expected_checkout_id, checkouts.first.id
|
26
|
+
assert_equal @expected_checkouts.size, checkouts.size
|
27
|
+
end
|
28
|
+
|
29
|
+
test ":complete completes a checkout" do
|
30
|
+
fake "checkouts/#{@expected_checkout_id}", method: :get, status: 200, body: load_fixture('checkout')
|
31
|
+
|
32
|
+
checkout = ShopifyAPI::Checkout.find(@expected_checkout_id)
|
33
|
+
|
34
|
+
fake "checkouts/#{@expected_checkout_id}/complete", method: :post, status: 200, body: load_fixture('checkouts')
|
35
|
+
|
36
|
+
checkout.complete
|
37
|
+
end
|
38
|
+
|
39
|
+
test ":ready? returns true when status is 201" do
|
40
|
+
fake "checkouts/#{@expected_checkout_id}", method: :get, status: 201, body: load_fixture('checkout')
|
41
|
+
checkout = ShopifyAPI::Checkout.find(@expected_checkout_id)
|
42
|
+
|
43
|
+
assert_predicate checkout, :ready?
|
44
|
+
end
|
45
|
+
|
46
|
+
test ":ready? returns false when status is 202" do
|
47
|
+
fake "checkouts/#{@expected_checkout_id}", method: :get, status: 202, body: load_fixture('checkout')
|
48
|
+
checkout = ShopifyAPI::Checkout.find(@expected_checkout_id)
|
49
|
+
|
50
|
+
refute_predicate checkout, :ready?
|
51
|
+
end
|
52
|
+
|
53
|
+
test ":payments returns payments for a checkout" do
|
54
|
+
fake "checkouts/#{@expected_checkout_id}", method: :get, status: 200, body: load_fixture('checkout')
|
55
|
+
checkout = ShopifyAPI::Checkout.find(@expected_checkout_id)
|
56
|
+
|
57
|
+
fake "checkouts/#{@expected_checkout_id}/payments", method: :get, status: 202, body: load_fixture('payments')
|
58
|
+
|
59
|
+
assert_equal 10.00, checkout.payments.first.amount
|
60
|
+
end
|
61
|
+
|
62
|
+
test ":shipping_rates returns shipping rates for a checkout" do
|
63
|
+
fake "checkouts/#{@expected_checkout_id}", method: :get, status: 200, body: load_fixture('checkout')
|
64
|
+
checkout = ShopifyAPI::Checkout.find(@expected_checkout_id)
|
65
|
+
|
66
|
+
fake("checkouts/#{@expected_checkout_id}/shipping_rates",
|
67
|
+
method: :get,
|
68
|
+
status: 202,
|
69
|
+
body: load_fixture('shipping_rates'))
|
70
|
+
assert_equal "canada_post-INT.TP.BOGUS-4.00", checkout.shipping_rates.first.id
|
8
71
|
end
|
9
72
|
end
|
@@ -8,6 +8,7 @@ class LogSubscriberTest < Test::Unit::TestCase
|
|
8
8
|
super
|
9
9
|
@page = { :page => { :id => 1, :title => 'Shopify API' } }.to_json
|
10
10
|
@ua_header = "\"User-Agent\"=>\"ShopifyAPI/#{ShopifyAPI::VERSION} ActiveResource/#{ActiveResource::VERSION::STRING} Ruby/#{RUBY_VERSION}\""
|
11
|
+
@ver_header = "\"X-Shopify-Checkout-Version\"=>\"2016-09-06\""
|
11
12
|
|
12
13
|
ShopifyAPI::Base.clear_session
|
13
14
|
ShopifyAPI::Base.site = "https://this-is-my-test-shop.myshopify.com/admin"
|
@@ -28,7 +29,7 @@ class LogSubscriberTest < Test::Unit::TestCase
|
|
28
29
|
assert_equal 4, @logger.logged(:info).size
|
29
30
|
assert_equal "GET https://this-is-my-test-shop.myshopify.com:443/admin/pages/1.json", @logger.logged(:info)[0]
|
30
31
|
assert_match /\-\-\> 200/, @logger.logged(:info)[1]
|
31
|
-
assert_equal "Headers: {\"Accept\"=>\"application/json\", #{@ua_header}}", @logger.logged(:info)[2]
|
32
|
+
assert_equal "Headers: {\"Accept\"=>\"application/json\", #{@ua_header}, #{@ver_header}}", @logger.logged(:info)[2]
|
32
33
|
assert_match /Response:\n\{\"page\"\:\{((\"id\"\:1)|(\"title\"\:\"Shopify API\")),((\"id\"\:1)|(\"title\"\:\"Shopify API\"))\}\}/, @logger.logged(:info)[3]
|
33
34
|
|
34
35
|
end
|
@@ -43,7 +44,7 @@ class LogSubscriberTest < Test::Unit::TestCase
|
|
43
44
|
assert_equal 4, @logger.logged(:info).size
|
44
45
|
assert_equal "GET https://this-is-my-test-shop.myshopify.com:443/admin/pages/2.json", @logger.logged(:info)[0]
|
45
46
|
assert_match /\-\-\> 404/, @logger.logged(:info)[1]
|
46
|
-
assert_equal "Headers: {\"Accept\"=>\"application/json\", #{@ua_header}}", @logger.logged(:info)[2]
|
47
|
+
assert_equal "Headers: {\"Accept\"=>\"application/json\", #{@ua_header}, #{@ver_header}}", @logger.logged(:info)[2]
|
47
48
|
assert_equal "Response:", @logger.logged(:info)[3]
|
48
49
|
end
|
49
50
|
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
{
|
2
|
+
"checkout": {
|
3
|
+
"buyer_accepts_marketing": false,
|
4
|
+
"cart_token": "68778783ad298f1c80c3bafcddeea02f",
|
5
|
+
"closed_at": null,
|
6
|
+
"completed_at": null,
|
7
|
+
"created_at": "2012-10-12T07:05:27-04:00",
|
8
|
+
"currency": "USD",
|
9
|
+
"email": "bob.norman@hostmail.com",
|
10
|
+
"gateway": null,
|
11
|
+
"id": 450789469,
|
12
|
+
"landing_site": null,
|
13
|
+
"note": null,
|
14
|
+
"referring_site": null,
|
15
|
+
"shipping_lines": [
|
16
|
+
{
|
17
|
+
"title": "Free Shipping",
|
18
|
+
"price": "0.00",
|
19
|
+
"code": "Free Shipping",
|
20
|
+
"source": "shopify"
|
21
|
+
}
|
22
|
+
],
|
23
|
+
"source": null,
|
24
|
+
"source_identifier": null,
|
25
|
+
"source_name": "web",
|
26
|
+
"source_url": null,
|
27
|
+
"subtotal_price": "398.00",
|
28
|
+
"taxes_included": false,
|
29
|
+
"token": "2a1ace52255252df566af0faaedfbfa7",
|
30
|
+
"total_discounts": "0.00",
|
31
|
+
"total_line_items_price": "398.00",
|
32
|
+
"total_price": "409.94",
|
33
|
+
"total_tax": "11.94",
|
34
|
+
"total_weight": 400,
|
35
|
+
"updated_at": "2012-10-12T07:05:27-04:00",
|
36
|
+
"line_items": [
|
37
|
+
{
|
38
|
+
"applied_discounts": [
|
39
|
+
|
40
|
+
],
|
41
|
+
"compare_at_price": null,
|
42
|
+
"fulfillment_service": "manual",
|
43
|
+
"gift_card": false,
|
44
|
+
"grams": 200,
|
45
|
+
"id": 49148385,
|
46
|
+
"line_price": "199.00",
|
47
|
+
"price": "199.00",
|
48
|
+
"product_id": 632910392,
|
49
|
+
"properties": null,
|
50
|
+
"quantity": 1,
|
51
|
+
"requires_shipping": true,
|
52
|
+
"sku": "IPOD2008RED",
|
53
|
+
"tax_lines": [
|
54
|
+
|
55
|
+
],
|
56
|
+
"taxable": true,
|
57
|
+
"title": "IPod Nano - 8GB",
|
58
|
+
"variant_id": 49148385,
|
59
|
+
"variant_title": "Red",
|
60
|
+
"vendor": "Apple"
|
61
|
+
},
|
62
|
+
{
|
63
|
+
"applied_discounts": [
|
64
|
+
|
65
|
+
],
|
66
|
+
"compare_at_price": null,
|
67
|
+
"fulfillment_service": "manual",
|
68
|
+
"gift_card": false,
|
69
|
+
"grams": 200,
|
70
|
+
"id": 808950810,
|
71
|
+
"line_price": "199.00",
|
72
|
+
"price": "199.00",
|
73
|
+
"product_id": 632910392,
|
74
|
+
"properties": null,
|
75
|
+
"quantity": 1,
|
76
|
+
"requires_shipping": true,
|
77
|
+
"sku": "IPOD2008PINK",
|
78
|
+
"tax_lines": [
|
79
|
+
|
80
|
+
],
|
81
|
+
"taxable": true,
|
82
|
+
"title": "IPod Nano - 8GB",
|
83
|
+
"variant_id": 808950810,
|
84
|
+
"variant_title": "Pink",
|
85
|
+
"vendor": "Apple"
|
86
|
+
}
|
87
|
+
],
|
88
|
+
"name": "#450789469",
|
89
|
+
"note_attributes": [
|
90
|
+
{
|
91
|
+
"name": "custom engraving",
|
92
|
+
"value": "Happy Birthday"
|
93
|
+
},
|
94
|
+
{
|
95
|
+
"name": "colour",
|
96
|
+
"value": "green"
|
97
|
+
}
|
98
|
+
],
|
99
|
+
"discount_codes": [
|
100
|
+
{
|
101
|
+
"code": "TENOFF",
|
102
|
+
"amount": "10.00"
|
103
|
+
}
|
104
|
+
],
|
105
|
+
"abandoned_checkout_url": "https://checkout.local/orders/690933842/2a1ace52255252df566af0faaedfbfa7?recovered=1",
|
106
|
+
"tax_lines": [
|
107
|
+
{
|
108
|
+
"price": "11.94",
|
109
|
+
"rate": 0.06,
|
110
|
+
"title": "State Tax"
|
111
|
+
}
|
112
|
+
],
|
113
|
+
"billing_address": {
|
114
|
+
"address1": "Chestnut Street 92",
|
115
|
+
"address2": "",
|
116
|
+
"city": "Louisville",
|
117
|
+
"company": null,
|
118
|
+
"country": "United States",
|
119
|
+
"first_name": "Bob",
|
120
|
+
"last_name": "Norman",
|
121
|
+
"latitude": "45.41634",
|
122
|
+
"longitude": "-75.6868",
|
123
|
+
"phone": "555-625-1199",
|
124
|
+
"province": "Kentucky",
|
125
|
+
"zip": "40202",
|
126
|
+
"name": "Bob Norman",
|
127
|
+
"country_code": "US",
|
128
|
+
"province_code": "KY"
|
129
|
+
},
|
130
|
+
"shipping_address": {
|
131
|
+
"address1": "Chestnut Street 92",
|
132
|
+
"address2": "",
|
133
|
+
"city": "Louisville",
|
134
|
+
"company": null,
|
135
|
+
"country": "United States",
|
136
|
+
"first_name": "Bob",
|
137
|
+
"last_name": "Norman",
|
138
|
+
"latitude": "45.41634",
|
139
|
+
"longitude": "-75.6868",
|
140
|
+
"phone": "555-625-1199",
|
141
|
+
"province": "Kentucky",
|
142
|
+
"zip": "40202",
|
143
|
+
"name": "Bob Norman",
|
144
|
+
"country_code": "US",
|
145
|
+
"province_code": "KY"
|
146
|
+
},
|
147
|
+
"customer": {
|
148
|
+
"accepts_marketing": false,
|
149
|
+
"created_at": "2014-03-07T16:12:37-05:00",
|
150
|
+
"email": "bob.norman@hostmail.com",
|
151
|
+
"first_name": "Bob",
|
152
|
+
"id": 207119551,
|
153
|
+
"last_name": "Norman",
|
154
|
+
"last_order_id": null,
|
155
|
+
"multipass_identifier": null,
|
156
|
+
"note": null,
|
157
|
+
"orders_count": 0,
|
158
|
+
"state": "disabled",
|
159
|
+
"total_spent": "0.00",
|
160
|
+
"updated_at": "2014-03-07T16:12:37-05:00",
|
161
|
+
"verified_email": true,
|
162
|
+
"tags": "",
|
163
|
+
"last_order_name": null,
|
164
|
+
"default_address": {
|
165
|
+
"address1": "Chestnut Street 92",
|
166
|
+
"address2": "",
|
167
|
+
"city": "Louisville",
|
168
|
+
"company": null,
|
169
|
+
"country": "United States",
|
170
|
+
"first_name": null,
|
171
|
+
"id": 207119551,
|
172
|
+
"last_name": null,
|
173
|
+
"phone": "555-625-1199",
|
174
|
+
"province": "Kentucky",
|
175
|
+
"zip": "40202",
|
176
|
+
"name": null,
|
177
|
+
"province_code": "KY",
|
178
|
+
"country_code": "US",
|
179
|
+
"country_name": "United States",
|
180
|
+
"default": true
|
181
|
+
}
|
182
|
+
}
|
183
|
+
}
|
184
|
+
}
|