workarea-flow_io 1.2.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.
Files changed (272) hide show
  1. checksums.yaml +7 -0
  2. data/.eslintignore +2 -0
  3. data/.eslintrc.json +37 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  5. data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
  6. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  7. data/.github/workflows/ci.yml +90 -0
  8. data/.gitignore +21 -0
  9. data/.rubocop.yml +2 -0
  10. data/.ruby-version +1 -0
  11. data/.stylelintrc.json +12 -0
  12. data/CHANGELOG.md +200 -0
  13. data/Gemfile +19 -0
  14. data/LICENSE +52 -0
  15. data/README.md +200 -0
  16. data/Rakefile +59 -0
  17. data/app/assets/javascripts/workarea/storefront/flow_io/adapters/flow_io_adapter.js +61 -0
  18. data/app/assets/javascripts/workarea/storefront/flow_io/configuration.js.erb +10 -0
  19. data/app/assets/javascripts/workarea/storefront/flow_io/flow.js +91 -0
  20. data/app/assets/stylesheets/flow_io/storefront/country_picker.scss +189 -0
  21. data/app/controllers/workarea/admin/application_controller.decorator +5 -0
  22. data/app/controllers/workarea/admin/catalog_categories_controller.decorator +9 -0
  23. data/app/controllers/workarea/admin/flow_imports_controller.rb +9 -0
  24. data/app/controllers/workarea/admin/orders_controller.decorator +6 -0
  25. data/app/controllers/workarea/admin/pricing_skus_controller.decorator +7 -0
  26. data/app/controllers/workarea/admin/search_settings_controller.decorator +27 -0
  27. data/app/controllers/workarea/storefront/application_controller.decorator +80 -0
  28. data/app/controllers/workarea/storefront/checkouts_controller.decorator +38 -0
  29. data/app/controllers/workarea/storefront/flow_io_webhook_controller.rb +49 -0
  30. data/app/controllers/workarea/storefront/recent_views_controller.decorator +15 -0
  31. data/app/controllers/workarea/storefront/searches_controller.decorator +11 -0
  32. data/app/helpers/workarea/admin/flow_helper.rb +13 -0
  33. data/app/helpers/workarea/storefront/flow_analytics_helper.rb +23 -0
  34. data/app/helpers/workarea/storefront/flow_content_helper.rb +21 -0
  35. data/app/middleware/workarea/flow_io/session_middleware.rb +68 -0
  36. data/app/models/workarea/address.decorator +12 -0
  37. data/app/models/workarea/catalog/category.decorator +8 -0
  38. data/app/models/workarea/checkout.decorator +26 -0
  39. data/app/models/workarea/flow_io/experience_geo.rb +18 -0
  40. data/app/models/workarea/flow_io/experience_summary.rb +15 -0
  41. data/app/models/workarea/flow_io/import.rb +31 -0
  42. data/app/models/workarea/flow_io/imported_item.rb +124 -0
  43. data/app/models/workarea/flow_io/local_item.rb +28 -0
  44. data/app/models/workarea/flow_io/localized_price.rb +30 -0
  45. data/app/models/workarea/flow_io/price.rb +12 -0
  46. data/app/models/workarea/flow_io/price_with_base.rb +7 -0
  47. data/app/models/workarea/flow_io/webhook/shared_secret.rb +12 -0
  48. data/app/models/workarea/flow_price_adjustment_set.rb +80 -0
  49. data/app/models/workarea/fulfillment.decorator +63 -0
  50. data/app/models/workarea/order.decorator +39 -0
  51. data/app/models/workarea/order/item.decorator +43 -0
  52. data/app/models/workarea/payment.decorator +11 -0
  53. data/app/models/workarea/payment/authorize/flow_payment.rb +48 -0
  54. data/app/models/workarea/payment/capture/flow_payment.rb +35 -0
  55. data/app/models/workarea/payment/flow_payment_data.rb +25 -0
  56. data/app/models/workarea/payment/flow_payment_operation.rb +20 -0
  57. data/app/models/workarea/payment/purchase/flow_payment.rb +44 -0
  58. data/app/models/workarea/payment/refund/flow_payment.rb +42 -0
  59. data/app/models/workarea/payment/store_flow_credit_card.rb +34 -0
  60. data/app/models/workarea/payment/tender.decorator +8 -0
  61. data/app/models/workarea/payment/tender/flow_payment.rb +15 -0
  62. data/app/models/workarea/payment/transaction.decorator +12 -0
  63. data/app/models/workarea/pricing/calculators/flow_localization_calculator.rb +30 -0
  64. data/app/models/workarea/pricing/calculators/item_calculator.decorator +39 -0
  65. data/app/models/workarea/pricing/collection.decorator +113 -0
  66. data/app/models/workarea/pricing/order_totals.decorator +53 -0
  67. data/app/models/workarea/pricing/price.decorator +17 -0
  68. data/app/models/workarea/pricing/price_distributor.decorator +51 -0
  69. data/app/models/workarea/pricing/request.decorator +17 -0
  70. data/app/models/workarea/pricing/shipping_totals.decorator +24 -0
  71. data/app/models/workarea/pricing/sku.decorator +46 -0
  72. data/app/models/workarea/search/settings.decorator +8 -0
  73. data/app/models/workarea/search/storefront/product.decorator +25 -0
  74. data/app/models/workarea/shipping.decorator +28 -0
  75. data/app/queries/workarea/order_metrics.decorator +23 -0
  76. data/app/queries/workarea/search/product_search.decorator +14 -0
  77. data/app/queries/workarea/search/storefront_search/response.decorator +40 -0
  78. data/app/services/workarea/flow_io/checkout.rb +242 -0
  79. data/app/services/workarea/flow_io/checkout_token_form.rb +36 -0
  80. data/app/services/workarea/flow_io/countries.rb +14 -0
  81. data/app/services/workarea/flow_io/detailed_shipping_notification_form.rb +84 -0
  82. data/app/services/workarea/flow_io/experiences.rb +24 -0
  83. data/app/services/workarea/flow_io/fulfillment_cancellation_form.rb +40 -0
  84. data/app/services/workarea/flow_io/item.rb +122 -0
  85. data/app/services/workarea/flow_io/item_importer.rb +108 -0
  86. data/app/services/workarea/flow_io/line_item_form.rb +72 -0
  87. data/app/services/workarea/flow_io/order_put_form.rb +62 -0
  88. data/app/services/workarea/flow_io/price_applier.rb +81 -0
  89. data/app/services/workarea/flow_io/price_applier/item_applier.rb +157 -0
  90. data/app/services/workarea/flow_io/routing_contraints.rb +10 -0
  91. data/app/services/workarea/flow_io/session.rb +90 -0
  92. data/app/services/workarea/flow_io/webhook.rb +28 -0
  93. data/app/services/workarea/flow_io/webhook/experience_deleted_v2.rb +9 -0
  94. data/app/services/workarea/flow_io/webhook/experience_upserted_v2.rb +9 -0
  95. data/app/services/workarea/flow_io/webhook/order_upserted_v2.rb +36 -0
  96. data/app/services/workarea/flow_io/webhook_request_signature.rb +19 -0
  97. data/app/view_models/workarea/admin/flow_imports_view_model.rb +36 -0
  98. data/app/view_models/workarea/storefront/cart_view_model.decorator +27 -0
  99. data/app/view_models/workarea/storefront/content_blocks/category_summary_view_model.decorator +11 -0
  100. data/app/view_models/workarea/storefront/content_blocks/product_insights_view_model.decorator +11 -0
  101. data/app/view_models/workarea/storefront/content_blocks/product_list_view_model.decorator +13 -0
  102. data/app/view_models/workarea/storefront/order_item_view_model.decorator +35 -0
  103. data/app/view_models/workarea/storefront/order_view_model.decorator +51 -0
  104. data/app/view_models/workarea/storefront/product_templates/option_set_view_model.decorator +20 -0
  105. data/app/view_models/workarea/storefront/product_templates/package_view_model.decorator +14 -0
  106. data/app/view_models/workarea/storefront/product_view_model.decorator +15 -0
  107. data/app/view_models/workarea/storefront/product_view_model/cache_key.decorator +7 -0
  108. data/app/view_models/workarea/storefront/recommendations_view_model.decorator +20 -0
  109. data/app/view_models/workarea/storefront/user_activity_view_model.decorator +18 -0
  110. data/app/views/workarea/admin/catalog_categories/edit.html.haml +85 -0
  111. data/app/views/workarea/admin/facets/_price_inputs.html.haml +50 -0
  112. data/app/views/workarea/admin/flow_imports/index.html.haml +44 -0
  113. data/app/views/workarea/admin/orders/_flow.html.haml +22 -0
  114. data/app/views/workarea/admin/orders/_flow_aux_navigation.html.haml +2 -0
  115. data/app/views/workarea/admin/orders/flow.html.haml +109 -0
  116. data/app/views/workarea/admin/orders/tenders/_flow_payment.html.haml +3 -0
  117. data/app/views/workarea/admin/pricing_skus/_cards.html.haml +83 -0
  118. data/app/views/workarea/admin/pricing_skus/flow.html.haml +60 -0
  119. data/app/views/workarea/admin/search_settings/show.html.haml +55 -0
  120. data/app/views/workarea/admin/shared/_flow_imports_link.html.haml +1 -0
  121. data/app/views/workarea/storefront/_flow_io_country_picker.html.haml +2 -0
  122. data/app/views/workarea/storefront/_flow_io_country_picker_javascript.html.haml +1 -0
  123. data/app/views/workarea/storefront/order_mailer/tenders/_flow_payment.html.haml +2 -0
  124. data/app/views/workarea/storefront/order_mailer/tenders/_flow_payment.text.erb +1 -0
  125. data/app/views/workarea/storefront/orders/tenders/_flow_payment.html.haml +3 -0
  126. data/app/views/workarea/storefront/products/_pricing.html.haml +41 -0
  127. data/app/workers/workarea/flow_io/delete_items.rb +30 -0
  128. data/app/workers/workarea/flow_io/fetch_import.rb +34 -0
  129. data/app/workers/workarea/flow_io/fulfillment_cancellation.rb +14 -0
  130. data/app/workers/workarea/flow_io/item_exporter.rb +47 -0
  131. data/app/workers/workarea/flow_io/process_import.rb +28 -0
  132. data/app/workers/workarea/flow_io/shipping_notifications.rb +13 -0
  133. data/bin/rails +25 -0
  134. data/config/initializers/appends.rb +39 -0
  135. data/config/initializers/freedom_patches.rb +23 -0
  136. data/config/initializers/middleware.rb +11 -0
  137. data/config/initializers/payment_proxy.rb +5 -0
  138. data/config/initializers/rack_attack.rb +15 -0
  139. data/config/initializers/scheduled_jobs.rb +9 -0
  140. data/config/initializers/workarea.rb +101 -0
  141. data/config/initializers/workarea_i18n.rb +11 -0
  142. data/config/locales/en.yml +72 -0
  143. data/config/routes.rb +21 -0
  144. data/lib/active_merchant/billing/bogus_flow_gateway.rb +16 -0
  145. data/lib/active_merchant/billing/flow_gateway.rb +48 -0
  146. data/lib/tasks/flow_io.rake +117 -0
  147. data/lib/workarea/flow_io.rb +73 -0
  148. data/lib/workarea/flow_io/bogus_client.rb +57 -0
  149. data/lib/workarea/flow_io/bogus_client/checkout_tokens.rb +25 -0
  150. data/lib/workarea/flow_io/bogus_client/experiences.rb +152 -0
  151. data/lib/workarea/flow_io/bogus_client/fulfillments.rb +9 -0
  152. data/lib/workarea/flow_io/bogus_client/items.rb +11 -0
  153. data/lib/workarea/flow_io/bogus_client/orders.rb +499 -0
  154. data/lib/workarea/flow_io/bogus_client/organizations.rb +42 -0
  155. data/lib/workarea/flow_io/bogus_client/proxy_client.rb +29 -0
  156. data/lib/workarea/flow_io/bogus_client/sessions.rb +115 -0
  157. data/lib/workarea/flow_io/bogus_client/shipping_notifications.rb +10 -0
  158. data/lib/workarea/flow_io/bogus_client/webhook_settings.rb +11 -0
  159. data/lib/workarea/flow_io/bogus_client/webhooks.rb +11 -0
  160. data/lib/workarea/flow_io/controller_log_subscriber.rb +21 -0
  161. data/lib/workarea/flow_io/engine.rb +8 -0
  162. data/lib/workarea/flow_io/http_handler.rb +27 -0
  163. data/lib/workarea/flow_io/version.rb +5 -0
  164. data/lib/workarea/freedom_patches/flow_io.rb +53 -0
  165. data/package.json +9 -0
  166. data/script/admin_ci +9 -0
  167. data/script/ci +11 -0
  168. data/script/core_ci +9 -0
  169. data/script/plugins_ci +9 -0
  170. data/script/storefront_ci +9 -0
  171. data/test/dummy/.ruby-version +1 -0
  172. data/test/dummy/Rakefile +6 -0
  173. data/test/dummy/bin/bundle +3 -0
  174. data/test/dummy/bin/rails +4 -0
  175. data/test/dummy/bin/rake +4 -0
  176. data/test/dummy/bin/setup +28 -0
  177. data/test/dummy/bin/update +28 -0
  178. data/test/dummy/bin/yarn +11 -0
  179. data/test/dummy/config.ru +5 -0
  180. data/test/dummy/config/application.rb +32 -0
  181. data/test/dummy/config/boot.rb +5 -0
  182. data/test/dummy/config/cable.yml +10 -0
  183. data/test/dummy/config/environment.rb +5 -0
  184. data/test/dummy/config/environments/development.rb +52 -0
  185. data/test/dummy/config/environments/production.rb +88 -0
  186. data/test/dummy/config/environments/test.rb +45 -0
  187. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  188. data/test/dummy/config/initializers/assets.rb +14 -0
  189. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  190. data/test/dummy/config/initializers/content_security_policy.rb +25 -0
  191. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  192. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  193. data/test/dummy/config/initializers/inflections.rb +16 -0
  194. data/test/dummy/config/initializers/mime_types.rb +4 -0
  195. data/test/dummy/config/initializers/workarea.rb +5 -0
  196. data/test/dummy/config/initializers/wrap_parameters.rb +9 -0
  197. data/test/dummy/config/locales/en.yml +33 -0
  198. data/test/dummy/config/puma.rb +34 -0
  199. data/test/dummy/config/routes.rb +5 -0
  200. data/test/dummy/config/secrets.yml +22 -0
  201. data/test/dummy/config/spring.rb +6 -0
  202. data/test/dummy/db/seeds.rb +2 -0
  203. data/test/dummy/log/.keep +0 -0
  204. data/test/dummy/package.json +5 -0
  205. data/test/factories/workarea/flow_io.rb +136 -0
  206. data/test/factories/workarea/flow_io/euro_order_upserted_payload.rb +581 -0
  207. data/test/fixtures/files/example.csv +14 -0
  208. data/test/integration/workarea/admin/flow_imports_integration_test.rb +20 -0
  209. data/test/integration/workarea/admin/flow_order_integration_test.rb +37 -0
  210. data/test/integration/workarea/admin/search_settings_integration_test.decorator +44 -0
  211. data/test/integration/workarea/flow_locale_integration_test.rb +34 -0
  212. data/test/integration/workarea/storefront/copying_guest_order_integration_test.decorator +113 -0
  213. data/test/integration/workarea/storefront/flow_io_order_redirect_test.rb +55 -0
  214. data/test/integration/workarea/storefront/flow_io_session_integration_test.rb +122 -0
  215. data/test/integration/workarea/storefront/flow_io_webhooks/order_integration_test.rb +750 -0
  216. data/test/integration/workarea/storefront/flow_webhook_rack_attack_integration_test.rb +54 -0
  217. data/test/integration/workarea/storefront/search_integration_test.decorator +51 -0
  218. data/test/javascripts/flow_spec.js +39 -0
  219. data/test/javascripts/spec_helper.js +3 -0
  220. data/test/models/workarea/address_test.decorator +20 -0
  221. data/test/models/workarea/checkout_test.decorator +20 -0
  222. data/test/models/workarea/flow_io/imported_item_test.rb +50 -0
  223. data/test/models/workarea/fulfillment_test.decorator +12 -0
  224. data/test/models/workarea/oms_fulfillment_test.decorator +14 -0
  225. data/test/models/workarea/order/item_test.decorator +46 -0
  226. data/test/models/workarea/order_test.decorator +16 -0
  227. data/test/models/workarea/payment/flow_payment_integration_test.rb +163 -0
  228. data/test/models/workarea/price_adjustment_set_flow_test.rb +8 -0
  229. data/test/models/workarea/pricing/calculators/flow_localization_calculator_test.rb +152 -0
  230. data/test/models/workarea/pricing/calculators/item_calculator_test.decorator +59 -0
  231. data/test/models/workarea/pricing/collection_test.decorator +140 -0
  232. data/test/models/workarea/pricing/order_totals_test.rb +247 -0
  233. data/test/models/workarea/pricing/price_distributor_test.decorator +21 -0
  234. data/test/models/workarea/pricing/sku_test.decorator +113 -0
  235. data/test/models/workarea/shipping_test.decorator +70 -0
  236. data/test/queries/workarea/flow_order_metrics_test.rb +104 -0
  237. data/test/services/workarea/commit_shipments_test.decorator +14 -0
  238. data/test/services/workarea/flow_io/checkout_test.rb +43 -0
  239. data/test/services/workarea/flow_io/detailed_shipping_notification_form_test.rb +145 -0
  240. data/test/services/workarea/flow_io/experiences_test.rb +14 -0
  241. data/test/services/workarea/flow_io/fulfillment_cancellation_form_test.rb +46 -0
  242. data/test/services/workarea/flow_io/item_importer_test.rb +357 -0
  243. data/test/services/workarea/flow_io/item_test.rb +72 -0
  244. data/test/services/workarea/flow_io/line_item_form_test.rb +34 -0
  245. data/test/services/workarea/flow_io/order_put_form_test.rb +48 -0
  246. data/test/services/workarea/flow_io/price_applier_test.rb +916 -0
  247. data/test/support/flow_fixtures.rb +1362 -0
  248. data/test/support/webhook_integration_test.rb +43 -0
  249. data/test/support/workarea/flow_bogus_client_support.rb +18 -0
  250. data/test/support/workarea/flow_io_vcr_config.rb +22 -0
  251. data/test/system/workarea/admin/search_fulfillment_system_test.decorator +25 -0
  252. data/test/system/workarea/storefront/analytics_system_test.decorator +28 -0
  253. data/test/system/workarea/storefront/flow_cart_recommendations_system_test.rb +70 -0
  254. data/test/system/workarea/storefront/users_flow_orders_system_test.rb +25 -0
  255. data/test/teaspoon_env.rb +6 -0
  256. data/test/test_helper.rb +27 -0
  257. data/test/vcr_cassettes/payment/flow/auth_capture.yml +188 -0
  258. data/test/vcr_cassettes/payment/flow/auth_capture_refund.yml +249 -0
  259. data/test/vcr_cassettes/payment/flow/auth_void.yml +188 -0
  260. data/test/vcr_cassettes/payment/flow/purchase_refund.yml +249 -0
  261. data/test/vcr_cassettes/payment/flow/store_auth.yml +127 -0
  262. data/test/vcr_cassettes/payment/flow/store_purchase.yml +188 -0
  263. data/test/view_models/workarea/storefront/cart_view_model_test.decorator +19 -0
  264. data/test/view_models/workarea/storefront/order_item_view_model_test.decorator +24 -0
  265. data/test/view_models/workarea/storefront/order_view_model_test.decorator +41 -0
  266. data/test/view_models/workarea/storefront/package_view_model_test.decorator +11 -0
  267. data/test/workers/workarea/flow_io/delete_items_test.rb +37 -0
  268. data/test/workers/workarea/flow_io/fetch_import_test.rb +41 -0
  269. data/test/workers/workarea/flow_io/item_exporter_test.rb +47 -0
  270. data/test/workers/workarea/flow_io/process_import_test.rb +25 -0
  271. data/workarea-flow_io.gemspec +20 -0
  272. metadata +375 -0
@@ -0,0 +1,36 @@
1
+ module Workarea
2
+ module FlowIo
3
+ class CheckoutTokenForm
4
+ def self.from(order:, session_id:)
5
+ new(order: order, session_id: session_id).to_flow_model
6
+ end
7
+
8
+ attr_reader :order, :session_id
9
+
10
+ def initialize(order:, session_id:)
11
+ @order = order
12
+ @session_id = session_id
13
+ end
14
+
15
+ def to_flow_model
16
+ ::Io::Flow::V0::Models::CheckoutTokenReferenceForm.new(attributes)
17
+ end
18
+
19
+ def attributes
20
+ {
21
+ order_number: order.id,
22
+ session_id: session_id,
23
+ urls: {
24
+ continue_shopping: continue_shopping_url
25
+ }
26
+ }
27
+ end
28
+
29
+ private
30
+
31
+ def continue_shopping_url
32
+ "https://#{Workarea.config.host}"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,14 @@
1
+ module Workarea
2
+ module FlowIo
3
+ class Countries
4
+ def self.all
5
+ # @return [Io::Flow::V0::Models::Country]
6
+ Rails.cache.fetch('flow-countries', expires_in: Workarea.config.cache_expirations.flow_io_country_cache) do
7
+ FlowIo.client
8
+ .organizations
9
+ .get_countries_by_organization(Workarea::FlowIo.organization_id)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,84 @@
1
+ module Workarea
2
+ module FlowIo
3
+ class DetailedShippingNotificationForm
4
+ attr_reader :id, :fulfillment
5
+
6
+ def self.from(id:, tracking_number:)
7
+ order = Workarea::Order.find id
8
+ shipping = Workarea::Shipping.find_by_order id
9
+ fulfillment = Workarea::Fulfillment.find id
10
+
11
+ new(order: order, shipping: shipping, fulfillment: fulfillment, tracking_number: tracking_number).to_flow_model
12
+ end
13
+
14
+ attr_reader :order, :shipping, :fulfillment, :tracking_number
15
+
16
+ def initialize(order:, shipping:, fulfillment:, tracking_number:)
17
+ @order = order
18
+ @shipping = shipping
19
+ @fulfillment = fulfillment
20
+ @tracking_number = tracking_number
21
+ end
22
+
23
+ # @return ::Io::Flow::V0::Models::DetailedShippingNotificationForm
24
+ def to_flow_model
25
+ ::Io::Flow::V0::Models::DetailedShippingNotificationForm.new(
26
+ attributes: { number: order.id },
27
+ carrier_tracking_number: tracking_number,
28
+ destination: {
29
+ contact: {
30
+ name: {
31
+ first: shipping_address.first_name,
32
+ last: shipping_address.last_name
33
+ },
34
+ phone: shipping_address.phone_number
35
+ },
36
+ location: {
37
+ streets: [shipping_address.street, shipping_address.street_2].compact,
38
+ city: shipping_address.city,
39
+ province: shipping_address.region,
40
+ postal: shipping_address.postal_code,
41
+ country: shipping_address.country.alpha3
42
+ }
43
+ },
44
+ order_number: order.id,
45
+ package: package,
46
+ service: shipping.shipping_service.service_code
47
+ )
48
+ end
49
+
50
+ private
51
+
52
+ def shipping_address
53
+ shipping&.address
54
+ end
55
+
56
+ def workarea_package
57
+ @workarea_package ||= Storefront::PackageViewModel.wrap(
58
+ fulfillment.find_package(tracking_number),
59
+ order: order
60
+ )
61
+ end
62
+
63
+ def discounts
64
+ @discounts ||= Pricing::Discount
65
+ .where(:_id.in => order.discount_ids)
66
+ .to_a
67
+ end
68
+
69
+ # TODO - IMPROVEMENT if using workarea-oms send package information
70
+ #
71
+ def package
72
+ {
73
+ dimensions: {},
74
+ items: workarea_package.items.map do |fulfillment_item_view_model|
75
+ FlowIo::LineItemForm.from(
76
+ order_item: fulfillment_item_view_model,
77
+ discounts: discounts
78
+ )
79
+ end
80
+ }
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,24 @@
1
+ module Workarea
2
+ module FlowIo
3
+ class Experiences
4
+ def self.all
5
+ # @return [::Io::Flow::V0::Models::Experience]
6
+ Rails.cache.fetch("flow-expereinces-#{FlowIo.organization_id}", expires_in: 1.hour) do
7
+ FlowIo.client.experiences.get(FlowIo.organization_id).select do |experience|
8
+ experience.status.value == "active"
9
+ end
10
+ end
11
+ end
12
+
13
+ def self.refresh_cache
14
+ Rails.cache.delete("flow-expereinces-#{FlowIo.organization_id}")
15
+ Experiences.all
16
+ end
17
+
18
+ # @return [String]
19
+ def self.all_currencies
20
+ Experiences.all.map(&:currency).uniq
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,40 @@
1
+ module Workarea
2
+ module FlowIo
3
+ class FulfillmentCancellationForm
4
+ def self.from(id:, quantities:)
5
+ order = Workarea::Order.find id
6
+
7
+ new(order: order, quantities: quantities).to_flow_model
8
+ end
9
+
10
+ attr_reader :order, :quantities
11
+
12
+ def initialize(order:, quantities:)
13
+ @order = order
14
+ @quantities = quantities
15
+ end
16
+
17
+ # @return ::Io::Flow::V0::Models::FulfillmentCancellationForm
18
+ def to_flow_model
19
+ ::Io::Flow::V0::Models::FulfillmentCancellationForm.new(
20
+ reason: "consumer_requested",
21
+ lines: lines
22
+ )
23
+ end
24
+
25
+ private
26
+
27
+ def lines
28
+ @lines ||= quantities.map do |order_item_id, quantity|
29
+ order_item = order.items.detect { |item| item.id.to_s == order_item_id.to_s }
30
+ next unless order_item.present?
31
+
32
+ {
33
+ item_number: order_item.sku,
34
+ quantity: quantity.to_i
35
+ }
36
+ end.compact
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,122 @@
1
+ module Workarea
2
+ module FlowIo
3
+ class Item
4
+ include ActionView::Helpers::AssetUrlHelper
5
+ include Core::Engine.routes.url_helpers
6
+ include Workarea::ApplicationHelper
7
+
8
+ attr_reader :product, :sku
9
+ delegate :name, :description, to: :product
10
+
11
+ def initialize(product, sku)
12
+ @product = product
13
+ @sku = sku
14
+ end
15
+
16
+ def form
17
+ ::Io::Flow::V0::Models::ItemForm.new(self.to_h)
18
+ end
19
+
20
+ def to_h
21
+ {
22
+ number: sku,
23
+ locale: FlowIo.config.original_locale,
24
+ name: name,
25
+ currency: pricing_sku.sell_price.currency.iso_code,
26
+ price: price,
27
+ categories: categories,
28
+ attributes: attributes,
29
+ dimensions: dimensions,
30
+ images: images
31
+ }
32
+ end
33
+
34
+ private
35
+
36
+ def variant
37
+ @variant ||= product.variants.find_by(sku: sku)
38
+ end
39
+
40
+ def shipping_sku
41
+ @shipping_sku ||= Shipping::Sku.find(sku) rescue nil
42
+ end
43
+
44
+ def pricing_sku
45
+ @pricing_sku ||= Pricing::Sku.find(sku) rescue Pricing::Sku.new(id: sku)
46
+ end
47
+
48
+ def price
49
+ pricing_sku.sell_price.dollars.to_f
50
+ end
51
+
52
+ def categories
53
+ @categories ||= Categorization.new(product).to_models.map(&:name)
54
+ end
55
+
56
+ def attributes
57
+ variant_attributes.merge(
58
+ "product_id" => product.id,
59
+ "msrp" => pricing_sku.msrp&.dollars&.to_f,
60
+ "regular_price" => sku_price.regular.dollars.to_f,
61
+ "sale_price" => sku_price.sale&.dollars&.to_f,
62
+ "fulfillment_method" => product.digital ? "digital" : "physical"
63
+ ).compact.map { |k, v| [k, v.to_s] }.to_h
64
+ end
65
+
66
+ def dimensions
67
+ return unless shipping_sku.present?
68
+
69
+ spatial_dimensions =
70
+ if shipping_sku.dimensions.present?
71
+ {
72
+ depth: { value: shipping_sku.height, units: shipping_sku.length_units },
73
+ length: { value: shipping_sku.length, units: shipping_sku.length_units },
74
+ width: { value: shipping_sku.width, units: shipping_sku.length_units },
75
+ }
76
+ else
77
+ {}
78
+ end
79
+
80
+ weight =
81
+ if shipping_sku.weight.present?
82
+ { weight: { value: shipping_sku.weight, units: shipping_sku.weight_units } }
83
+ else
84
+ {}
85
+ end
86
+
87
+ { packing: spatial_dimensions.merge(weight) }
88
+ end
89
+
90
+ def variant_specific_images
91
+ @variant_specific_images ||=
92
+ begin
93
+ sku_options = variant.details.values.flat_map { |options| options.map(&:optionize) }
94
+
95
+ product.images.select do |image|
96
+ sku_options.include?(image.option.optionize)
97
+ end
98
+ end
99
+ end
100
+
101
+ def images
102
+ @images ||= (variant_specific_images || [product.images.first]).flat_map do |image|
103
+ FlowIo.image_sizes.map do |processor, tags|
104
+ { url: product_image_url(image, processor), tags: tags }
105
+ end
106
+ end
107
+ end
108
+
109
+ def sku_price
110
+ @sku_price ||= pricing_sku.find_price(quantity: 1)
111
+ end
112
+
113
+ def variant_attributes
114
+ variant.details.map { |k, v| [k, v.join(', ')] }.to_h
115
+ end
116
+
117
+ def mounted_core
118
+ self
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,108 @@
1
+ module Workarea
2
+ module FlowIo
3
+ class ItemImporter
4
+ def self.perform!(item)
5
+ new(item).perform!
6
+ end
7
+
8
+ attr_reader :item
9
+
10
+ def initialize(item)
11
+ @item = item
12
+ end
13
+
14
+ def perform!
15
+ if local_item.present?
16
+ local_item.update_attributes local_item_attributes
17
+ else
18
+ pricing_sku.flow_io_local_items.create!(local_item_attributes)
19
+ end
20
+ Sidekiq::Callbacks.disable(Workarea::FlowIo::ItemExporter) do
21
+ pricing_sku.save
22
+ end
23
+ end
24
+
25
+ private
26
+ delegate :local, to: :item
27
+ delegate :experience, to: :local
28
+
29
+ def sku
30
+ item.number
31
+ end
32
+
33
+ def pricing_sku
34
+ @pricing_sku ||= Pricing::Sku.find sku
35
+ end
36
+
37
+ def local_item
38
+ @local_item ||= pricing_sku
39
+ .flow_io_local_items
40
+ .detect { |li| li.experience.key == experience.key }
41
+ end
42
+
43
+ def pricing_attributes
44
+ @pricing_attributes || local.price_attributes.symbolize_keys
45
+ end
46
+
47
+ def msrp_attributes
48
+ @msrp_attributes ||= pricing_attributes[:msrp]
49
+ end
50
+
51
+ def msrp
52
+ return {} unless msrp_attributes.present?
53
+
54
+ {
55
+ msrp: {
56
+ price: msrp_attributes.to_m,
57
+ label: msrp_attributes.label,
58
+ base_currency: { price: msrp_attributes.base.to_m, label: msrp_attributes.base.label }
59
+ }
60
+ }
61
+ end
62
+
63
+ def local_item_attributes
64
+ {
65
+ experience: {
66
+ id: experience.id,
67
+ key: experience.key,
68
+ name: experience.name,
69
+ country: Country.find_country_by_alpha3(experience.country),
70
+ currency: experience.currency,
71
+ language: experience.language
72
+ },
73
+ prices: prices
74
+ }.merge(msrp)
75
+ end
76
+
77
+ def prices
78
+ regular = pricing_attributes[:regular_price]
79
+ sale = pricing_attributes[:sale_price]
80
+
81
+ price = {
82
+ min_quantity: 1,
83
+ regular: {
84
+ price: regular.to_m,
85
+ label: regular.label,
86
+ base_currency: {
87
+ price: regular.base.to_m,
88
+ label: regular.base.label
89
+ }
90
+ }
91
+ }
92
+
93
+ if sale.present?
94
+ price[:sale] = {
95
+ price: sale.to_m,
96
+ label: sale.label,
97
+ base_currency: {
98
+ price: sale.base.to_m,
99
+ label: sale.base.label
100
+ }
101
+ }
102
+ end
103
+
104
+ [price]
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,72 @@
1
+ module Workarea
2
+ module FlowIo
3
+ class LineItemForm
4
+ def self.from(order_item:, discounts:)
5
+ new(order_item: order_item, discounts: discounts).to_flow_model
6
+ end
7
+
8
+ attr_reader :order_item, :discounts
9
+
10
+ def initialize(order_item:, discounts:)
11
+ @order_item = order_item
12
+ @discounts = discounts
13
+ end
14
+
15
+ def price
16
+ ::Io::Flow::V0::Models::Money.new(
17
+ amount: base_item_price.cents,
18
+ currency: base_item_price.currency.to_s
19
+ )
20
+ end
21
+
22
+ def to_h
23
+ {
24
+ number: order_item.sku,
25
+ quantity: order_item.quantity,
26
+ price: price,
27
+ discounts: discounts_form
28
+ }
29
+ end
30
+
31
+ def to_flow_model
32
+ ::Io::Flow::V0::Models::LineItemForm.new(to_h)
33
+ end
34
+
35
+ private
36
+
37
+ # Discount price adjustments for the order_item
38
+ #
39
+ # @return [Array<Workarea::PriceAdjustment>]
40
+ #
41
+ def discount_price_adjustments
42
+ order_item.price_adjustments.discounts
43
+ end
44
+
45
+ def base_item_price
46
+ order_item
47
+ .flow_price_adjustments
48
+ .adjusting('item')
49
+ .reject(&:discount?)
50
+ .sum
51
+ end
52
+
53
+ def discounts_form
54
+ ::Io::Flow::V0::Models::DiscountsForm.new(
55
+ discounts: discount_price_adjustments.map do |discount_price_adjustment|
56
+ {
57
+ offer: {
58
+ money: {
59
+ amount: discount_price_adjustment.amount.abs.to_f,
60
+ currency: discount_price_adjustment.amount.currency.iso_code
61
+ },
62
+ discriminator: ::Io::Flow::V0::Models::DiscountOffer::Types::DISCOUNT_OFFER_FIXED
63
+ },
64
+ target: "item",
65
+ label: discount_price_adjustment.description
66
+ }
67
+ end
68
+ )
69
+ end
70
+ end
71
+ end
72
+ end