duodealer_api 1.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.
Files changed (322) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +13 -0
  4. data/.rubocop.yml +8 -0
  5. data/.travis.yml +23 -0
  6. data/Gemfile +5 -0
  7. data/Gemfile_ar41 +5 -0
  8. data/Gemfile_ar50 +5 -0
  9. data/Gemfile_ar51 +5 -0
  10. data/Gemfile_ar_master +5 -0
  11. data/RELEASING +13 -0
  12. data/Rakefile +44 -0
  13. data/docker-compose.yml +13 -0
  14. data/docs/graphql.md +191 -0
  15. data/duodealer_api.gemspec +38 -0
  16. data/lib/active_resource/connection_ext.rb +10 -0
  17. data/lib/active_resource/detailed_log_subscriber.rb +52 -0
  18. data/lib/active_resource/json_errors.rb +31 -0
  19. data/lib/duodealer_api.rb +33 -0
  20. data/lib/duodealer_api/api_version.rb +205 -0
  21. data/lib/duodealer_api/connection.rb +35 -0
  22. data/lib/duodealer_api/countable.rb +14 -0
  23. data/lib/duodealer_api/disable_prefix_check.rb +31 -0
  24. data/lib/duodealer_api/events.rb +7 -0
  25. data/lib/duodealer_api/graphql.rb +79 -0
  26. data/lib/duodealer_api/graphql/http_client.rb +22 -0
  27. data/lib/duodealer_api/graphql/railtie.rb +17 -0
  28. data/lib/duodealer_api/graphql/task.rake +97 -0
  29. data/lib/duodealer_api/limits.rb +76 -0
  30. data/lib/duodealer_api/message_enricher.rb +23 -0
  31. data/lib/duodealer_api/meta.rb +15 -0
  32. data/lib/duodealer_api/metafields.rb +20 -0
  33. data/lib/duodealer_api/paginated_collection.rb +69 -0
  34. data/lib/duodealer_api/pagination_link_headers.rb +33 -0
  35. data/lib/duodealer_api/resources.rb +3 -0
  36. data/lib/duodealer_api/resources/abandoned_checkout.rb +7 -0
  37. data/lib/duodealer_api/resources/access_scope.rb +10 -0
  38. data/lib/duodealer_api/resources/access_token.rb +8 -0
  39. data/lib/duodealer_api/resources/address.rb +4 -0
  40. data/lib/duodealer_api/resources/announcement.rb +4 -0
  41. data/lib/duodealer_api/resources/api_permission.rb +9 -0
  42. data/lib/duodealer_api/resources/application_charge.rb +15 -0
  43. data/lib/duodealer_api/resources/application_credit.rb +4 -0
  44. data/lib/duodealer_api/resources/array_base.rb +13 -0
  45. data/lib/duodealer_api/resources/article.rb +21 -0
  46. data/lib/duodealer_api/resources/asset.rb +100 -0
  47. data/lib/duodealer_api/resources/assigned_fulfillment_order.rb +16 -0
  48. data/lib/duodealer_api/resources/base.rb +162 -0
  49. data/lib/duodealer_api/resources/billing_address.rb +4 -0
  50. data/lib/duodealer_api/resources/blog.rb +10 -0
  51. data/lib/duodealer_api/resources/carrier_service.rb +4 -0
  52. data/lib/duodealer_api/resources/cart.rb +4 -0
  53. data/lib/duodealer_api/resources/checkout.rb +30 -0
  54. data/lib/duodealer_api/resources/collect.rb +6 -0
  55. data/lib/duodealer_api/resources/collection.rb +14 -0
  56. data/lib/duodealer_api/resources/collection_listing.rb +18 -0
  57. data/lib/duodealer_api/resources/collection_publication.rb +10 -0
  58. data/lib/duodealer_api/resources/comment.rb +9 -0
  59. data/lib/duodealer_api/resources/country.rb +4 -0
  60. data/lib/duodealer_api/resources/currency.rb +6 -0
  61. data/lib/duodealer_api/resources/custom_collection.rb +19 -0
  62. data/lib/duodealer_api/resources/customer.rb +29 -0
  63. data/lib/duodealer_api/resources/customer_group.rb +5 -0
  64. data/lib/duodealer_api/resources/customer_invite.rb +4 -0
  65. data/lib/duodealer_api/resources/customer_saved_search.rb +11 -0
  66. data/lib/duodealer_api/resources/discount_code.rb +9 -0
  67. data/lib/duodealer_api/resources/draft_order.rb +14 -0
  68. data/lib/duodealer_api/resources/draft_order_invoice.rb +4 -0
  69. data/lib/duodealer_api/resources/event.rb +8 -0
  70. data/lib/duodealer_api/resources/fulfillment.rb +47 -0
  71. data/lib/duodealer_api/resources/fulfillment_event.rb +15 -0
  72. data/lib/duodealer_api/resources/fulfillment_order.rb +137 -0
  73. data/lib/duodealer_api/resources/fulfillment_order_locations_for_move.rb +4 -0
  74. data/lib/duodealer_api/resources/fulfillment_request.rb +15 -0
  75. data/lib/duodealer_api/resources/fulfillment_service.rb +4 -0
  76. data/lib/duodealer_api/resources/fulfillment_v2.rb +20 -0
  77. data/lib/duodealer_api/resources/gift_card.rb +7 -0
  78. data/lib/duodealer_api/resources/image.rb +16 -0
  79. data/lib/duodealer_api/resources/inventory_item.rb +6 -0
  80. data/lib/duodealer_api/resources/inventory_level.rb +55 -0
  81. data/lib/duodealer_api/resources/line_item.rb +14 -0
  82. data/lib/duodealer_api/resources/location.rb +8 -0
  83. data/lib/duodealer_api/resources/marketing_event.rb +10 -0
  84. data/lib/duodealer_api/resources/metafield.rb +13 -0
  85. data/lib/duodealer_api/resources/note_attribute.rb +4 -0
  86. data/lib/duodealer_api/resources/option.rb +4 -0
  87. data/lib/duodealer_api/resources/order.rb +43 -0
  88. data/lib/duodealer_api/resources/order_risk.rb +8 -0
  89. data/lib/duodealer_api/resources/page.rb +6 -0
  90. data/lib/duodealer_api/resources/payment.rb +7 -0
  91. data/lib/duodealer_api/resources/payment_details.rb +4 -0
  92. data/lib/duodealer_api/resources/ping.rb +3 -0
  93. data/lib/duodealer_api/resources/policy.rb +7 -0
  94. data/lib/duodealer_api/resources/price_rule.rb +8 -0
  95. data/lib/duodealer_api/resources/product.rb +35 -0
  96. data/lib/duodealer_api/resources/product_listing.rb +16 -0
  97. data/lib/duodealer_api/resources/product_publication.rb +10 -0
  98. data/lib/duodealer_api/resources/province.rb +5 -0
  99. data/lib/duodealer_api/resources/publication.rb +5 -0
  100. data/lib/duodealer_api/resources/receipt.rb +4 -0
  101. data/lib/duodealer_api/resources/recurring_application_charge.rb +31 -0
  102. data/lib/duodealer_api/resources/redirect.rb +4 -0
  103. data/lib/duodealer_api/resources/refund.rb +14 -0
  104. data/lib/duodealer_api/resources/report.rb +4 -0
  105. data/lib/duodealer_api/resources/resource_feedback.rb +19 -0
  106. data/lib/duodealer_api/resources/rule.rb +4 -0
  107. data/lib/duodealer_api/resources/script_tag.rb +4 -0
  108. data/lib/duodealer_api/resources/shipping_address.rb +4 -0
  109. data/lib/duodealer_api/resources/shipping_line.rb +4 -0
  110. data/lib/duodealer_api/resources/shipping_rate.rb +7 -0
  111. data/lib/duodealer_api/resources/shipping_zone.rb +4 -0
  112. data/lib/duodealer_api/resources/shop.rb +25 -0
  113. data/lib/duodealer_api/resources/smart_collection.rb +19 -0
  114. data/lib/duodealer_api/resources/storefront_access_token.rb +4 -0
  115. data/lib/duodealer_api/resources/tax_line.rb +4 -0
  116. data/lib/duodealer_api/resources/tax_service.rb +4 -0
  117. data/lib/duodealer_api/resources/tender_transaction.rb +6 -0
  118. data/lib/duodealer_api/resources/theme.rb +4 -0
  119. data/lib/duodealer_api/resources/transaction.rb +5 -0
  120. data/lib/duodealer_api/resources/usage_charge.rb +5 -0
  121. data/lib/duodealer_api/resources/user.rb +4 -0
  122. data/lib/duodealer_api/resources/variant.rb +8 -0
  123. data/lib/duodealer_api/resources/webhook.rb +4 -0
  124. data/lib/duodealer_api/session.rb +171 -0
  125. data/lib/duodealer_api/version.rb +3 -0
  126. data/shipit.rubygems.yml +1 -0
  127. data/test/abandoned_checkouts_test.rb +29 -0
  128. data/test/access_scope_test.rb +23 -0
  129. data/test/access_token_test.rb +19 -0
  130. data/test/active_resource/json_errors_test.rb +19 -0
  131. data/test/api_permission_test.rb +9 -0
  132. data/test/api_version_test.rb +157 -0
  133. data/test/application_charge_test.rb +79 -0
  134. data/test/application_credit_test.rb +35 -0
  135. data/test/article_test.rb +73 -0
  136. data/test/asset_test.rb +18 -0
  137. data/test/assigned_fulfillment_order_test.rb +77 -0
  138. data/test/base_test.rb +198 -0
  139. data/test/blog_test.rb +8 -0
  140. data/test/carrier_service_test.rb +17 -0
  141. data/test/cart_test.rb +13 -0
  142. data/test/checkouts_test.rb +77 -0
  143. data/test/collect_test.rb +9 -0
  144. data/test/collection_listing_test.rb +79 -0
  145. data/test/collection_publication_test.rb +40 -0
  146. data/test/collection_test.rb +49 -0
  147. data/test/countable_test.rb +13 -0
  148. data/test/currency_test.rb +21 -0
  149. data/test/custom_collection_test.rb +9 -0
  150. data/test/customer_saved_search_test.rb +27 -0
  151. data/test/customer_test.rb +50 -0
  152. data/test/detailed_log_subscriber_test.rb +139 -0
  153. data/test/discount_code_test.rb +53 -0
  154. data/test/draft_order_test.rb +151 -0
  155. data/test/fixtures/abandoned_checkout.json +184 -0
  156. data/test/fixtures/abandoned_checkouts.json +186 -0
  157. data/test/fixtures/access_scopes.json +10 -0
  158. data/test/fixtures/access_token_delegate.json +4 -0
  159. data/test/fixtures/api_versions.json +38 -0
  160. data/test/fixtures/apis.json +42 -0
  161. data/test/fixtures/application_charge.json +16 -0
  162. data/test/fixtures/application_charges.json +57 -0
  163. data/test/fixtures/application_credit.json +12 -0
  164. data/test/fixtures/application_credits.json +24 -0
  165. data/test/fixtures/article.json +15 -0
  166. data/test/fixtures/articles.json +39 -0
  167. data/test/fixtures/asset.json +9 -0
  168. data/test/fixtures/assets.json +136 -0
  169. data/test/fixtures/assigned_fulfillment_orders.json +78 -0
  170. data/test/fixtures/authors.json +1 -0
  171. data/test/fixtures/blog.json +13 -0
  172. data/test/fixtures/blogs.json +13 -0
  173. data/test/fixtures/carrier_service.json +9 -0
  174. data/test/fixtures/carts.json +43 -0
  175. data/test/fixtures/checkout.json +160 -0
  176. data/test/fixtures/checkouts.json +162 -0
  177. data/test/fixtures/collect.json +12 -0
  178. data/test/fixtures/collection.json +17 -0
  179. data/test/fixtures/collection_listing.json +11 -0
  180. data/test/fixtures/collection_listing_product_ids.json +1 -0
  181. data/test/fixtures/collection_listing_product_ids2.json +1 -0
  182. data/test/fixtures/collection_listings.json +13 -0
  183. data/test/fixtures/collection_products.json +47 -0
  184. data/test/fixtures/collection_publication.json +11 -0
  185. data/test/fixtures/collection_publications.json +13 -0
  186. data/test/fixtures/currencies.json +25 -0
  187. data/test/fixtures/custom_collection.json +17 -0
  188. data/test/fixtures/customer_invite.json +9 -0
  189. data/test/fixtures/customer_saved_search.json +9 -0
  190. data/test/fixtures/customer_saved_search_customers.json +60 -0
  191. data/test/fixtures/customers.json +59 -0
  192. data/test/fixtures/customers_account_activation_url.json +3 -0
  193. data/test/fixtures/customers_search.json +60 -0
  194. data/test/fixtures/discount_code.json +10 -0
  195. data/test/fixtures/discount_codes.json +12 -0
  196. data/test/fixtures/draft_order.json +159 -0
  197. data/test/fixtures/draft_order_completed.json +159 -0
  198. data/test/fixtures/draft_order_invoice.json +9 -0
  199. data/test/fixtures/draft_orders.json +161 -0
  200. data/test/fixtures/engagement.json +15 -0
  201. data/test/fixtures/events.json +31 -0
  202. data/test/fixtures/fulfillment.json +49 -0
  203. data/test/fixtures/fulfillment_event.json +12 -0
  204. data/test/fixtures/fulfillment_order.json +38 -0
  205. data/test/fixtures/fulfillment_order_locations_for_move.json +18 -0
  206. data/test/fixtures/fulfillment_orders.json +78 -0
  207. data/test/fixtures/fulfillment_request.json +28 -0
  208. data/test/fixtures/fulfillment_service.json +10 -0
  209. data/test/fixtures/fulfillments.json +53 -0
  210. data/test/fixtures/gift_card.json +20 -0
  211. data/test/fixtures/gift_card_disabled.json +20 -0
  212. data/test/fixtures/graphql/2019-10.json +1083 -0
  213. data/test/fixtures/graphql/dummy_schema.rb +16 -0
  214. data/test/fixtures/graphql/unstable.json +1083 -0
  215. data/test/fixtures/image.json +10 -0
  216. data/test/fixtures/images.json +20 -0
  217. data/test/fixtures/inventory_level.json +7 -0
  218. data/test/fixtures/inventory_levels.json +24 -0
  219. data/test/fixtures/marketing_event.json +28 -0
  220. data/test/fixtures/marketing_events.json +54 -0
  221. data/test/fixtures/metafield.json +12 -0
  222. data/test/fixtures/metafields.json +34 -0
  223. data/test/fixtures/order.json +297 -0
  224. data/test/fixtures/order_risk.json +14 -0
  225. data/test/fixtures/order_risks.json +28 -0
  226. data/test/fixtures/order_with_properties.json +373 -0
  227. data/test/fixtures/orders.json +299 -0
  228. data/test/fixtures/payment.json +7 -0
  229. data/test/fixtures/payments.json +9 -0
  230. data/test/fixtures/ping/conversation.json +1 -0
  231. data/test/fixtures/ping/failed_delivery_confirmation.json +1 -0
  232. data/test/fixtures/ping/message.json +1 -0
  233. data/test/fixtures/ping/successful_delivery_confirmation.json +1 -0
  234. data/test/fixtures/policies.json +8 -0
  235. data/test/fixtures/price_rule.json +27 -0
  236. data/test/fixtures/price_rules.json +28 -0
  237. data/test/fixtures/product.json +116 -0
  238. data/test/fixtures/product_listing.json +86 -0
  239. data/test/fixtures/product_listing_product_ids.json +1 -0
  240. data/test/fixtures/product_listing_product_ids2.json +1 -0
  241. data/test/fixtures/product_listings.json +174 -0
  242. data/test/fixtures/product_publication.json +11 -0
  243. data/test/fixtures/product_publications.json +13 -0
  244. data/test/fixtures/publications.json +9 -0
  245. data/test/fixtures/recurring_application_charge.json +22 -0
  246. data/test/fixtures/recurring_application_charge_adjustment.json +5 -0
  247. data/test/fixtures/recurring_application_charges.json +106 -0
  248. data/test/fixtures/redirect.json +7 -0
  249. data/test/fixtures/refund.json +112 -0
  250. data/test/fixtures/report.json +9 -0
  251. data/test/fixtures/reports.json +11 -0
  252. data/test/fixtures/script_tag.json +10 -0
  253. data/test/fixtures/script_tags.json +18 -0
  254. data/test/fixtures/shipping_rates.json +12 -0
  255. data/test/fixtures/shipping_zones.json +315 -0
  256. data/test/fixtures/shop.json +26 -0
  257. data/test/fixtures/smart_collection.json +21 -0
  258. data/test/fixtures/smart_collection_products.json +155 -0
  259. data/test/fixtures/storefront_access_token.json +9 -0
  260. data/test/fixtures/storefront_access_tokens.json +18 -0
  261. data/test/fixtures/tags.json +1 -0
  262. data/test/fixtures/tax_service.json +9 -0
  263. data/test/fixtures/tender_transactions.json +52 -0
  264. data/test/fixtures/transaction.json +29 -0
  265. data/test/fixtures/usage_charge.json +11 -0
  266. data/test/fixtures/usage_charges.json +23 -0
  267. data/test/fixtures/user.json +21 -0
  268. data/test/fixtures/users.json +42 -0
  269. data/test/fixtures/variant.json +23 -0
  270. data/test/fixtures/variants.json +88 -0
  271. data/test/fixtures/webhook.json +10 -0
  272. data/test/fixtures/webhooks.json +18 -0
  273. data/test/fulfillment_event_test.rb +69 -0
  274. data/test/fulfillment_order_test.rb +462 -0
  275. data/test/fulfillment_order_test_helper.rb +7 -0
  276. data/test/fulfillment_request_test.rb +33 -0
  277. data/test/fulfillment_service_test.rb +17 -0
  278. data/test/fulfillment_test.rb +224 -0
  279. data/test/fulfillment_v2_test.rb +62 -0
  280. data/test/gift_card_test.rb +22 -0
  281. data/test/graphql/http_client_test.rb +26 -0
  282. data/test/graphql_test.rb +147 -0
  283. data/test/image_test.rb +39 -0
  284. data/test/inventory_level_test.rb +59 -0
  285. data/test/lib/webmock_extensions/last_request.rb +16 -0
  286. data/test/limits_test.rb +38 -0
  287. data/test/location_test.rb +14 -0
  288. data/test/marketing_event_test.rb +68 -0
  289. data/test/message_enricher_test.rb +45 -0
  290. data/test/meta_test.rb +49 -0
  291. data/test/metafield_test.rb +46 -0
  292. data/test/order_risk_test.rb +46 -0
  293. data/test/order_test.rb +125 -0
  294. data/test/pagination_test.rb +257 -0
  295. data/test/payment_test.rb +19 -0
  296. data/test/policy_test.rb +19 -0
  297. data/test/price_rule_test.rb +65 -0
  298. data/test/product_listing_test.rb +97 -0
  299. data/test/product_publication_test.rb +40 -0
  300. data/test/product_test.rb +60 -0
  301. data/test/publication_test.rb +12 -0
  302. data/test/recurring_application_charge_test.rb +142 -0
  303. data/test/redirect_test.rb +9 -0
  304. data/test/refund_test.rb +32 -0
  305. data/test/report_test.rb +35 -0
  306. data/test/resource_feedback_test.rb +42 -0
  307. data/test/script_tag_test.rb +30 -0
  308. data/test/session_test.rb +366 -0
  309. data/test/shipping_rate_test.rb +17 -0
  310. data/test/shipping_zone_test.rb +10 -0
  311. data/test/shop_test.rb +68 -0
  312. data/test/smart_collection_test.rb +35 -0
  313. data/test/storefront_access_token_test.rb +32 -0
  314. data/test/tax_service_test.rb +9 -0
  315. data/test/tender_transaction_test.rb +18 -0
  316. data/test/test_helper.rb +124 -0
  317. data/test/transaction_test.rb +17 -0
  318. data/test/usage_charge_test.rb +21 -0
  319. data/test/user_test.rb +17 -0
  320. data/test/variant_test.rb +46 -0
  321. data/test/webhook_test.rb +21 -0
  322. metadata +541 -0
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ require 'rails/railtie'
3
+
4
+ module DuodealerAPI
5
+ module GraphQL
6
+ class Railtie < Rails::Railtie
7
+ initializer 'duodealer_api.initialize_graphql_clients' do |app|
8
+ DuodealerAPI::GraphQL.schema_location = app.root.join('db', DuodealerAPI::GraphQL.schema_location)
9
+ DuodealerAPI::GraphQL.initialize_clients
10
+ end
11
+
12
+ rake_tasks do
13
+ load 'duodealer_api/graphql/task.rake'
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+ require 'fileutils'
3
+
4
+ namespace :duodealer_api do
5
+ namespace :graphql do
6
+ desc 'Dumps a local JSON schema file of the Duo Dealer Admin API'
7
+ task :dump do
8
+ usage = <<~USAGE
9
+
10
+ Usage: rake duodealer_api:graphql:dump [<args>]
11
+
12
+ Dumps a local JSON schema file of the Duo Dealer Admin API. The schema is specific to an
13
+ API version and authentication is required (either OAuth or private app).
14
+
15
+ Dump the schema file for the 2020-01 API version using private app authentication:
16
+ $ rake duodealer_api:graphql:dump SHOP_URL="https://API_KEY:PASSWORD@SHOP_NAME.duodealer.com" API_VERSION=2020-01
17
+
18
+ Dump the schema file for the unstable API version using an OAuth access token:
19
+ $ rake duodealer_api:graphql:dump SHOP_DOMAIN=SHOP_NAME.duodealer.com ACCESS_TOKEN=abc API_VERSION=unstable
20
+
21
+ Arguments:
22
+ ACCESS_TOKEN OAuth access token (shop specific)
23
+ API_VERSION API version handle [example: 2020-01]
24
+ SHOP_DOMAIN Shop domain (without path) [example: SHOP_NAME.duodealer.com]
25
+ SHOP_URL Shop URL for private apps [example: https://API_KEY:PASSWORD@SHOP_NAME.duodealer.com]
26
+ USAGE
27
+
28
+ access_token = ENV['ACCESS_TOKEN'] || ENV['access_token']
29
+ api_version = ENV['API_VERSION'] || ENV['api_version']
30
+ shop_url = ENV['SHOP_URL'] || ENV['shop_url']
31
+ shop_domain = ENV['SHOP_DOMAIN'] || ENV['shop_domain']
32
+
33
+ unless access_token || api_version || shop_url || shop_domain
34
+ puts usage
35
+ exit(1)
36
+ end
37
+
38
+ unless shop_url || shop_domain
39
+ puts 'Error: either SHOP_DOMAIN or SHOP_URL is required for authentication'
40
+ puts usage
41
+ exit(1)
42
+ end
43
+
44
+ if shop_url && shop_domain
45
+ puts 'Error: SHOP_DOMAIN and SHOP_URL cannot be used together. Use one or the other for authentication.'
46
+ puts usage
47
+ exit(1)
48
+ end
49
+
50
+ if shop_domain && !access_token
51
+ puts 'Error: ACCESS_TOKEN required when SHOP_DOMAIN is used'
52
+ puts usage
53
+ exit(1)
54
+ end
55
+
56
+ unless api_version
57
+ puts 'Error: API_VERSION required. Example: 2020-01'
58
+ puts usage
59
+ exit(1)
60
+ end
61
+
62
+ Rake::Task['environment'].invoke if Rake::Task.task_defined?('environment')
63
+
64
+ Duodealer::ApiVersion.fetch_known_versions
65
+ DuodealerAPI::ApiVersion.version_lookup_mode = :raise_on_unknown
66
+
67
+ duodealer_session = DuodealerAPI::Session.new(domain: shop_domain, token: access_token, api_version: api_version)
68
+ DuodealerAPI::Base.activate_session(duodealer_session)
69
+
70
+ if shop_url
71
+ DuodealerAPI::Base.site = shop_url
72
+ end
73
+
74
+ puts "Fetching schema for #{DuodealerAPI::Base.api_version.handle} API version..."
75
+
76
+ client = DuodealerAPI::GraphQL::HTTPClient.new(DuodealerAPI::Base.api_version)
77
+ document = GraphQL.parse('{ __schema { queryType { name } } }')
78
+ response = client.execute(document: document).to_h
79
+
80
+ unless response['data'].present?
81
+ puts "Error: failed to query the API."
82
+ puts "Response: #{response}"
83
+ puts 'Ensure your SHOP_DOMAIN or SHOP_URL are valid and you have valid authentication credentials.'
84
+ puts usage
85
+ exit(1)
86
+ end
87
+
88
+ schema_location = DuodealerAPI::GraphQL.schema_location
89
+ FileUtils.mkdir_p(schema_location) unless Dir.exist?(schema_location)
90
+
91
+ schema_file = schema_location.join("#{api_version}.json")
92
+ GraphQL::Client.dump_schema(client, schema_file.to_s)
93
+
94
+ puts "Wrote file #{schema_file}"
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,76 @@
1
+ module DuodealerAPI
2
+ module Limits
3
+ class LimitUnavailable < StandardError; end
4
+
5
+ def self.included(klass)
6
+ klass.send(:extend, ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ # Takes form <call count>/<bucket size>
11
+ # See https://help.duodealer.com/en/api/getting-started/api-call-limit
12
+ # Eg: 2/40
13
+ CREDIT_LIMIT_HEADER_PARAM = {
14
+ shop: 'X-DuoDealer-Shop-Api-Call-Limit',
15
+ }
16
+
17
+ ##
18
+ # How many more API calls can I make?
19
+ # @return {Integer}
20
+ #
21
+ def credit_left
22
+ credit_limit(:shop) - credit_used(:shop)
23
+ end
24
+ alias_method :available_calls, :credit_left
25
+
26
+ ##
27
+ # Have I reached my API call limit?
28
+ # @return {Boolean}
29
+ #
30
+ def credit_maxed?
31
+ credit_left <= 0
32
+ end
33
+ alias_method :maxed?, :credit_maxed?
34
+
35
+ ##
36
+ # How many total API calls can I make?
37
+ # NOTE: subtracting 1 from credit_limit because I think DuodealerAPI cuts off at 299 or shop limits.
38
+ # @param {Symbol} scope [:shop]
39
+ # @return {Integer}
40
+ #
41
+ def credit_limit(scope=:shop)
42
+ api_credit_limit_param(scope).pop.to_i - 1
43
+ end
44
+ alias_method :call_limit, :credit_limit
45
+
46
+ ##
47
+ # How many API calls have I made?
48
+ # @param {Symbol} scope [:shop]
49
+ # @return {Integer}
50
+ #
51
+ def credit_used(scope=:shop)
52
+ api_credit_limit_param(scope).shift.to_i
53
+ end
54
+ alias_method :call_count, :credit_used
55
+
56
+ ##
57
+ # @return {HTTPResonse}
58
+ #
59
+ def response
60
+ Shop.current unless DuodealerAPI::Base.connection.response
61
+ DuodealerAPI::Base.connection.response
62
+ end
63
+
64
+ private
65
+
66
+ ##
67
+ # @return {Array}
68
+ #
69
+ def api_credit_limit_param(scope)
70
+ header = response[CREDIT_LIMIT_HEADER_PARAM[scope]]
71
+ raise LimitUnavailable unless header
72
+ header.split('/')
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,23 @@
1
+ module DuodealerAPI
2
+ class MessageEnricher < SimpleDelegator
3
+ def message
4
+ return super unless (400...500).include?(code.to_i)
5
+
6
+ @_cached_message ||= begin
7
+ detailed_error = begin
8
+ parsed_body = JSON.parse(body)
9
+
10
+ if parsed_body['error']
11
+ parsed_body['error'].to_s
12
+ elsif parsed_body['errors']
13
+ Array(parsed_body['errors']).join('; ')
14
+ end
15
+ rescue JSON::ParserError
16
+ nil
17
+ end
18
+
19
+ detailed_error.present? ? "#{super} (#{detailed_error})" : super
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DuodealerAPI
4
+ class Meta < ActiveResource::Base
5
+ self.site = "https://app.duodealer.com/services/"
6
+ self.element_name = 'api'
7
+ self.primary_key = :handle
8
+ self.timeout = 5
9
+
10
+ def self.admin_versions
11
+ all.find { |api| api.handle = :admin }.versions
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,20 @@
1
+ module DuodealerAPI
2
+ module Metafields
3
+ def metafields(**options)
4
+ options.merge! resource: self.class.collection_name, resource_id: id
5
+
6
+ Metafield.find :all, params: options
7
+ end
8
+
9
+ def add_metafield(metafield)
10
+ raise ArgumentError, "You can only add metafields to resource that has been saved" if new?
11
+
12
+ metafield.prefix_options = {
13
+ :resource => self.class.collection_name,
14
+ :resource_id => id
15
+ }
16
+ metafield.save
17
+ metafield
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DuodealerAPI
4
+ class PaginatedCollection < ActiveResource::Collection
5
+ module CollectionPagination
6
+ def initialize(args)
7
+ @next_url = pagination_link_headers.next_link&.url&.to_s
8
+ @previous_url = pagination_link_headers.previous_link&.url&.to_s
9
+ super(args)
10
+ end
11
+
12
+ def next_page?
13
+ ensure_available
14
+ @next_url.present?
15
+ end
16
+
17
+ def previous_page?
18
+ ensure_available
19
+ @previous_url.present?
20
+ end
21
+
22
+ def fetch_next_page
23
+ fetch_page(@next_url)
24
+ end
25
+
26
+ def fetch_previous_page
27
+ fetch_page(@previous_url)
28
+ end
29
+
30
+ def next_page_info
31
+ extract_page_info(@next_url)
32
+ end
33
+
34
+ def previous_page_info
35
+ extract_page_info(@previous_url)
36
+ end
37
+
38
+ private
39
+
40
+ AVAILABLE_IN_VERSION = DuodealerAPI::ApiVersion.find_version('2019-10')
41
+ AVAILABLE_IN_VERSION_EARLY = DuodealerAPI::ApiVersion.find_version('2019-07')
42
+
43
+ def fetch_page(url)
44
+ ensure_available
45
+ return [] unless url.present?
46
+
47
+ resource_class.all(from: url)
48
+ end
49
+
50
+ def pagination_link_headers
51
+ @pagination_link_headers ||= DuodealerAPI::PaginationLinkHeaders.new(
52
+ DuodealerAPI::Base.connection.response["Link"]
53
+ )
54
+ end
55
+
56
+ def ensure_available
57
+ return if DuodealerAPI::Base.api_version >= AVAILABLE_IN_VERSION
58
+ return if DuodealerAPI::Base.api_version >= AVAILABLE_IN_VERSION_EARLY && resource_class.early_july_pagination?
59
+ raise NotImplementedError
60
+ end
61
+
62
+ def extract_page_info(url)
63
+ CGI.escape(Rack::Utils.parse_query(URI(url).query)['page_info']) if url.present?
64
+ end
65
+ end
66
+
67
+ include CollectionPagination
68
+ end
69
+ end
@@ -0,0 +1,33 @@
1
+ module DuodealerAPI
2
+ class InvalidPaginationLinksError < StandardError; end
3
+
4
+ class PaginationLinkHeaders
5
+ LinkHeader = Struct.new(:url, :rel)
6
+ attr_reader :previous_link, :next_link
7
+
8
+ def initialize(link_header)
9
+ links = parse_link_header(link_header)
10
+ @previous_link = links.find { |link| link.rel == :previous }
11
+ @next_link = links.find { |link| link.rel == :next }
12
+
13
+ self
14
+ end
15
+
16
+ private
17
+
18
+ def parse_link_header(link_header)
19
+ return [] unless link_header.present?
20
+ links = link_header.split(',')
21
+ links.map do |link|
22
+ parts = link.split('; ')
23
+ raise DuodealerAPI::InvalidPaginationLinksError.new("Invalid link header: url and rel expected") unless parts.length == 2
24
+
25
+ url = parts[0][/<(.*)>/, 1]
26
+ rel = parts[1][/rel="(.*)"/, 1]&.to_sym
27
+
28
+ url = URI.parse(url)
29
+ LinkHeader.new(url, rel)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ require 'duodealer_api/resources/base'
2
+ require 'duodealer_api/resources/array_base'
3
+ Dir.glob("#{File.dirname(__FILE__)}/resources/*").each { |file| require(file) }
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DuodealerAPI
4
+ class AbandonedCheckout < Base
5
+ self.element_name = "checkout"
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ module DuodealerAPI
3
+ class AccessScope < Base
4
+ class << self
5
+ def prefix(_options={})
6
+ '/admin/oauth/'
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ module DuodealerAPI
2
+ class AccessToken < Base
3
+ def self.delegate(access_scope, expires_in = nil)
4
+ resource = post(:delegate, delegate_access_scope: access_scope, expires_in: expires_in)
5
+ instantiate_record(format.decode(resource.body), {})
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ module DuodealerAPI
2
+ class Address < Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DuodealerAPI
2
+ class Announcement < Base
3
+ end
4
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DuodealerAPI
4
+ class ApiPermission < Base
5
+ def self.destroy
6
+ delete(:current)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ module DuodealerAPI
2
+ class ApplicationCharge < Base
3
+ undef_method :test
4
+
5
+ class << self
6
+ [:pending, :expired, :accepted, :declined].each do |status|
7
+ define_method(status) { (all || []).select { |c| c.status == status.to_s } }
8
+ end
9
+ end
10
+
11
+ def activate
12
+ load_attributes_from_response(post(:activate))
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ module DuodealerAPI
2
+ class ApplicationCredit < Base
3
+ end
4
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DuodealerAPI
4
+ class ArrayBase < Base
5
+ class << self
6
+ private
7
+
8
+ def instantiate_record(record, *)
9
+ record
10
+ end
11
+ end
12
+ end
13
+ end