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,12 @@
1
+ module Workarea
2
+ module FlowIo
3
+ class Price
4
+ include ApplicationDocument
5
+
6
+ field :price, type: Money
7
+ field :label, type: String
8
+
9
+ validates_presence_of :price, :label
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ module Workarea
2
+ module FlowIo
3
+ class PriceWithBase < Price
4
+ embeds_one :base_currency, class_name: "Workarea::FlowIo::Price"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ module Workarea
2
+ module FlowIo
3
+ class Webhook
4
+ class SharedSecret
5
+ include ApplicationDocument
6
+ include UrlToken
7
+
8
+ validates :token, presence: true
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,80 @@
1
+ module Workarea
2
+ class FlowPriceAdjustmentSet < Array
3
+ attr_reader :experience
4
+
5
+ # @param [Workarea::PriceAdjustment] price_adjustments
6
+ # @param (::Io::Flow::V0::Models::ExperienceSummary || ::Io::Flow::V0::Models::ExperienceGeo) experience
7
+ #
8
+ def initialize(price_adjustments, experience)
9
+ super(price_adjustments)
10
+ @experience = experience
11
+ end
12
+
13
+ def select(*args)
14
+ self.class.new(super, experience)
15
+ end
16
+
17
+ def reject(*args)
18
+ self.class.new(super, experience)
19
+ end
20
+
21
+ def adjusting(type)
22
+ select { |a| a.price == type }
23
+ end
24
+
25
+ def sum
26
+ super(&:amount).to_m(experience.currency)
27
+ end
28
+
29
+ def discounts
30
+ select(&:discount?)
31
+ end
32
+
33
+ def +(val)
34
+ self.class.new(to_a + val.to_a, experience)
35
+ end
36
+
37
+ def reduce_by_description(type)
38
+ amounts = adjusting(type).reduce({}) do |memo, adjustment|
39
+ memo[adjustment.description] ||= 0.to_m(experience.currency)
40
+ memo[adjustment.description] += adjustment.amount
41
+ memo
42
+ end
43
+
44
+ self.class.new(
45
+ amounts.keys.map do |description|
46
+ PriceAdjustment.new(
47
+ description: description,
48
+ amount: amounts[description]
49
+ )
50
+ end,
51
+ experience
52
+ )
53
+ end
54
+
55
+ def taxable_share_for(adjustment)
56
+ return 0.to_m(experience.currency) if taxable_total.zero?
57
+
58
+ discount_share = adjustment.amount / taxable_total
59
+ discount_amount = discount_total * discount_share
60
+ adjustment.amount - discount_amount
61
+ end
62
+
63
+ def grouped_by_parent
64
+ each_with_object({}) do |adjustment, memo|
65
+ memo[adjustment._parent] ||= PriceAdjustmentSet.new
66
+ memo[adjustment._parent] << adjustment
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def taxable_total
73
+ reject { |a| a.discount? || a.data['tax_code'].blank? }.sum(&:amount).to_m(experience.currency)
74
+ end
75
+
76
+ def discount_total
77
+ discounts.sum(&:amount).to_m(experience.currency).abs
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,63 @@
1
+ module Workarea
2
+ decorate Fulfillment, with: :flow_io do
3
+
4
+ def ship_items(tracking_number, shipped_items)
5
+ shipped_items.each do |shipped_item|
6
+ mark_item_shipped(
7
+ shipped_item.merge(tracking_number: tracking_number.downcase)
8
+ )
9
+ end
10
+
11
+ save.tap do |result|
12
+ if result && Workarea.config.send_transactional_emails
13
+ Storefront::FulfillmentMailer
14
+ .shipped(id, tracking_number)
15
+ .deliver_later
16
+ end
17
+
18
+ if result
19
+ Workarea::FlowIo::ShippingNotifications.perform_async(id, tracking_number)
20
+ end
21
+ end
22
+ end
23
+
24
+ def cancel_items(canceled_items)
25
+ return unless canceled_items.present?
26
+
27
+ occured_at = Time.current
28
+
29
+ canceled_items = canceled_items.map do |canceled_item|
30
+ canceled_item = canceled_item.with_indifferent_access
31
+ next unless canceled_item['quantity'].to_i > 0
32
+
33
+ item = items.detect { |i| i.order_item_id == canceled_item['id'].to_s }
34
+ next unless item.present?
35
+
36
+ item.events.build(
37
+ status: 'canceled',
38
+ quantity: canceled_item['quantity'],
39
+ created_at: occured_at,
40
+ updated_at: occured_at,
41
+ data: canceled_item.except('id', 'quantity')
42
+ )
43
+ [canceled_item['id'].to_s, canceled_item['quantity']]
44
+ end.compact
45
+
46
+ return unless canceled_items.present?
47
+
48
+ result = save
49
+
50
+ if result && Workarea.config.send_transactional_emails
51
+ Storefront::FulfillmentMailer
52
+ .canceled(id, Hash[canceled_items])
53
+ .deliver_later
54
+ end
55
+
56
+ if result
57
+ Workarea::FlowIo::FulfillmentCancellation.perform_async(id, Hash[canceled_items])
58
+ end
59
+
60
+ result
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,39 @@
1
+ module Workarea
2
+ decorate Order, with: :flow_io do
3
+ decorated do
4
+ embeds_one :experience,
5
+ class_name: "Workarea::FlowIo::ExperienceGeo",
6
+ as: :experienceable
7
+
8
+ field :flow, type: Boolean, default: false
9
+ field :flow_checkout_token, type: String
10
+
11
+ field :flow_subtotal_price, type: Money
12
+ field :flow_shipping_total, type: Money
13
+ field :flow_tax_total, type: Money
14
+ field :flow_total_value, type: Money
15
+ field :flow_total_price, type: Money
16
+ end
17
+
18
+ def currency
19
+ experience&.currency || Money.default_currency.iso_code
20
+ end
21
+
22
+ # All flow price adjustments on this order.
23
+ #
24
+ # @return [FlowPriceAdjustmentSet]
25
+ #
26
+ def flow_price_adjustments
27
+ FlowPriceAdjustmentSet.new(items.flat_map(&:flow_price_adjustments), experience)
28
+ end
29
+
30
+ def build_experience_from_flow_model(experience_geo)
31
+ if experience_geo.present?
32
+ country = Country.find_country_by_alpha3(experience_geo.country)
33
+ build_experience(experience_geo.to_hash.merge(country: country))
34
+ else
35
+ self.experience = nil
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ module Workarea
2
+ decorate Order::Item, with: :flow do
3
+ decorated do
4
+ field :flow_total_value, type: Money
5
+ field :flow_total_price, type: Money
6
+
7
+ embeds_many :flow_price_adjustments,
8
+ class_name: 'Workarea::PriceAdjustment',
9
+ extend: PriceAdjustmentExtension
10
+ end
11
+
12
+ def reset_price_adjustments
13
+ __build__(:price_adjustments, [], relations["price_adjustments"])
14
+ end
15
+
16
+ def reset_flow_price_adjustments
17
+ __build__(:flow_price_adjustments, [], relations["flow_price_adjustments"])
18
+ end
19
+
20
+ # Adds a flow price adjustment to the item. Does not persist.
21
+ #
22
+ # @return [self]
23
+ #
24
+ def adjust_flow_pricing(options = {})
25
+ flow_price_adjustments.build(options)
26
+ end
27
+
28
+ # The flow unit price of the item including all currently attached
29
+ # flow price adjustments.
30
+ #
31
+ # @return [Money]
32
+ #
33
+ def current_flow_unit_price
34
+ return 0.to_m(order.currency) if flow_price_adjustments.blank?
35
+
36
+ flow_price_adjustments
37
+ .adjusting('item')
38
+ .map(&:unit)
39
+ .sum
40
+ .to_m(order.currency)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,11 @@
1
+ module Workarea
2
+ decorate Payment, with: :flow_io do
3
+ decorated do
4
+ field :operation_tender_type, type: String
5
+
6
+ embeds_one :flow_payment,
7
+ class_name: "Workarea::Payment::Tender::FlowPayment"
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,48 @@
1
+ module Workarea
2
+ class Payment
3
+ module Authorize
4
+ class FlowPayment
5
+ include OperationImplementation
6
+ include FlowPaymentOperation
7
+ include FlowPaymentData
8
+
9
+ delegate :address, to: :tender
10
+
11
+ def complete!
12
+ # Some gateways will tokenize in the same request as the authorize.
13
+ # If that is the case for the gateway you are implementing, omit the
14
+ # following line, and save the token on the tender after doing the
15
+ # gateway authorization.
16
+ return unless StoreFlowCreditCard.new(tender, options).save!
17
+
18
+ transaction.response = handle_active_merchant_errors do
19
+ gateway.authorize(
20
+ tender.to_token_or_active_merchant,
21
+ order_id,
22
+ transaction_options
23
+ )
24
+ end
25
+ end
26
+
27
+ def cancel!
28
+ return unless transaction.success?
29
+
30
+ transaction.cancellation = handle_active_merchant_errors do
31
+ gateway.void(nil, transaction.response.authorization)
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def transaction_options
38
+ {
39
+ amount: transaction.amount.to_f,
40
+ currency: currency_code,
41
+ customer: customer_data,
42
+ discriminator: :direct_authorization_form
43
+ }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,35 @@
1
+ module Workarea
2
+ class Payment
3
+ class Capture
4
+ class FlowPayment
5
+ include OperationImplementation
6
+ include FlowPaymentOperation
7
+ include FlowPaymentData
8
+
9
+ def complete!
10
+ validate_reference!
11
+
12
+ transaction.response = handle_active_merchant_errors do
13
+ gateway.capture(
14
+ transaction.amount.to_f,
15
+ transaction.reference.response.authorization,
16
+ transaction_options
17
+ )
18
+ end
19
+ end
20
+
21
+ def cancel!
22
+ # noop, can't cancel a capture
23
+ end
24
+
25
+ private
26
+
27
+ def transaction_options
28
+ {
29
+ currency: currency_code
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ module Workarea
2
+ class Payment
3
+ module FlowPaymentData
4
+ def order
5
+ @order ||= Workarea::Order.find(tender.payment.id)
6
+ end
7
+
8
+ def order_id
9
+ @order_id ||= order.id
10
+ end
11
+
12
+ def currency_code
13
+ order.currency
14
+ end
15
+
16
+ def customer_data
17
+ {
18
+ customer: {
19
+ name: { first: address.first_name , last: address.last_name }
20
+ }
21
+ }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ module Workarea
2
+ class Payment
3
+ module FlowPaymentOperation
4
+ def handle_active_merchant_errors
5
+ begin
6
+ yield
7
+ rescue ActiveMerchant::ResponseError => error
8
+ error.response
9
+ rescue ActiveMerchant::ActiveMerchantError,
10
+ ActiveMerchant::ConnectionError => error
11
+ ActiveMerchant::Billing::Response.new(false, nil)
12
+ end
13
+ end
14
+
15
+ def gateway
16
+ Workarea::FlowIo.gateway
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ module Workarea
2
+ class Payment
3
+ module Purchase
4
+ class FlowPayment
5
+ include OperationImplementation
6
+ include FlowPaymentOperation
7
+ include FlowPaymentData
8
+
9
+ delegate :address, to: :tender
10
+
11
+ def complete!
12
+ # Some gateways will tokenize in the same request as the auth/capture.
13
+ # If that is the case for the gateway you are implementing, omit the
14
+ # following line, and save the token on the tender after doing the
15
+ # gateway authorization.
16
+ return unless StoreFlowCreditCard.new(tender, options).save!
17
+
18
+ transaction.response = handle_active_merchant_errors do
19
+ gateway.purchase(
20
+ tender.to_token_or_active_merchant,
21
+ order_id,
22
+ transaction_options
23
+ )
24
+ end
25
+ end
26
+
27
+ def cancel!
28
+ # can't void a capture
29
+ end
30
+
31
+ private
32
+
33
+ def transaction_options
34
+ {
35
+ amount: transaction.amount.cents,
36
+ currency: currency_code,
37
+ customer: customer_data,
38
+ discriminator: :direct_authorization_form
39
+ }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end