workarea-listrak 5.0.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 (163) hide show
  1. checksums.yaml +7 -0
  2. data/.eslintrc.json +36 -0
  3. data/.esvmrc +5 -0
  4. data/.gitignore +32 -0
  5. data/CHANGELOG.md +322 -0
  6. data/Gemfile +14 -0
  7. data/README.md +130 -0
  8. data/Rakefile +53 -0
  9. data/app/assets/javascripts/workarea/admin/modules/listrak/list_events_select.js +83 -0
  10. data/app/assets/javascripts/workarea/storefront/listrak/adapters/listrak_adapter.js +110 -0
  11. data/app/assets/javascripts/workarea/storefront/listrak/listrak_config.js.erb +13 -0
  12. data/app/assets/javascripts/workarea/storefront/listrak/modules/listrak.js +64 -0
  13. data/app/controllers/workarea/admin/listrak/configurations_controller.rb +30 -0
  14. data/app/controllers/workarea/admin/listrak/events_controller.rb +17 -0
  15. data/app/helpers/workarea/listrak/analytics/helper.rb +44 -0
  16. data/app/models/workarea/listrak/configuration.rb +19 -0
  17. data/app/queries/workarea/categorization.decorator +7 -0
  18. data/app/services/workarea/listrak/data_api/customers.rb +26 -0
  19. data/app/services/workarea/listrak/data_api/orders.rb +26 -0
  20. data/app/services/workarea/listrak/data_api/products.rb +26 -0
  21. data/app/services/workarea/listrak/data_api.rb +63 -0
  22. data/app/services/workarea/listrak/email_api/contacts.rb +73 -0
  23. data/app/services/workarea/listrak/email_api/events.rb +44 -0
  24. data/app/services/workarea/listrak/email_api/lists.rb +21 -0
  25. data/app/services/workarea/listrak/email_api/messages.rb +50 -0
  26. data/app/services/workarea/listrak/email_api/transactional_messages.rb +32 -0
  27. data/app/services/workarea/listrak/email_api.rb +71 -0
  28. data/app/services/workarea/listrak/models/address.rb +83 -0
  29. data/app/services/workarea/listrak/models/contact.rb +67 -0
  30. data/app/services/workarea/listrak/models/contact_form.rb +24 -0
  31. data/app/services/workarea/listrak/models/customer_form.rb +209 -0
  32. data/app/services/workarea/listrak/models/event.rb +45 -0
  33. data/app/services/workarea/listrak/models/event_form.rb +25 -0
  34. data/app/services/workarea/listrak/models/list.rb +204 -0
  35. data/app/services/workarea/listrak/models/message_form.rb +147 -0
  36. data/app/services/workarea/listrak/models/order_form.rb +352 -0
  37. data/app/services/workarea/listrak/models/order_item.rb +197 -0
  38. data/app/services/workarea/listrak/models/product_form.rb +369 -0
  39. data/app/services/workarea/listrak/models/transactional_message_form.rb +21 -0
  40. data/app/services/workarea/listrak/oauth.rb +45 -0
  41. data/app/services/workarea/listrak/transactional_message.rb +83 -0
  42. data/app/view_models/workarea/admin/listrak_configuration_view_model.rb +17 -0
  43. data/app/views/workarea/admin/listrak/configurations/edit.html.haml +28 -0
  44. data/app/views/workarea/admin/listrak/events/index.json.jbuilder +4 -0
  45. data/app/views/workarea/admin/shared/_listrak_configuration_link.html.haml +1 -0
  46. data/app/views/workarea/storefront/checkouts/_listrak.html.haml +2 -0
  47. data/app/workers/workarea/listrak/customer_exporter.rb +22 -0
  48. data/app/workers/workarea/listrak/order_exporter.rb +22 -0
  49. data/app/workers/workarea/listrak/product_exporter.rb +50 -0
  50. data/app/workers/workarea/listrak/subscribe_email_signup.rb +34 -0
  51. data/app/workers/workarea/listrak/unsubscribe_email_signup.rb +27 -0
  52. data/bin/rails +18 -0
  53. data/bin/rake +16 -0
  54. data/bin/rspec +16 -0
  55. data/bin/rubocop +16 -0
  56. data/config/initializers/append_points.rb +28 -0
  57. data/config/initializers/configuration.rb +8 -0
  58. data/config/locales/en.yml +17 -0
  59. data/config/routes.rb +10 -0
  60. data/docs/Listrak Technical Integration Guide.docx +0 -0
  61. data/lib/generators/workarea/listrak/message/USAGE +9 -0
  62. data/lib/generators/workarea/listrak/message/message_generator.rb +15 -0
  63. data/lib/generators/workarea/listrak/message/templates/message.rb.erb +24 -0
  64. data/lib/workarea/listrak/analytics.rb +17 -0
  65. data/lib/workarea/listrak/bogus_data_api/customers.rb +9 -0
  66. data/lib/workarea/listrak/bogus_data_api/orders.rb +9 -0
  67. data/lib/workarea/listrak/bogus_data_api/products.rb +9 -0
  68. data/lib/workarea/listrak/bogus_data_api/proxy_client.rb +29 -0
  69. data/lib/workarea/listrak/bogus_data_api.rb +46 -0
  70. data/lib/workarea/listrak/bogus_email_api/contacts.rb +8 -0
  71. data/lib/workarea/listrak/bogus_email_api/events.rb +23 -0
  72. data/lib/workarea/listrak/bogus_email_api/lists.rb +63 -0
  73. data/lib/workarea/listrak/bogus_email_api/proxy_client.rb +29 -0
  74. data/lib/workarea/listrak/bogus_email_api/transactional_messages.rb +9 -0
  75. data/lib/workarea/listrak/bogus_email_api.rb +51 -0
  76. data/lib/workarea/listrak/engine.rb +12 -0
  77. data/lib/workarea/listrak/error.rb +39 -0
  78. data/lib/workarea/listrak/version.rb +5 -0
  79. data/lib/workarea/listrak.rb +57 -0
  80. data/readme/listrak-admin.png +0 -0
  81. data/script/admin_ci +9 -0
  82. data/script/ci +11 -0
  83. data/script/core_ci +9 -0
  84. data/script/plugins_ci +9 -0
  85. data/script/storefront_ci +9 -0
  86. data/test/dummy/Rakefile +6 -0
  87. data/test/dummy/bin/bundle +3 -0
  88. data/test/dummy/bin/rails +4 -0
  89. data/test/dummy/bin/rake +4 -0
  90. data/test/dummy/bin/setup +34 -0
  91. data/test/dummy/bin/update +29 -0
  92. data/test/dummy/config/application.rb +18 -0
  93. data/test/dummy/config/boot.rb +5 -0
  94. data/test/dummy/config/cable.yml +9 -0
  95. data/test/dummy/config/environment.rb +5 -0
  96. data/test/dummy/config/environments/development.rb +54 -0
  97. data/test/dummy/config/environments/production.rb +86 -0
  98. data/test/dummy/config/environments/test.rb +43 -0
  99. data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
  100. data/test/dummy/config/initializers/assets.rb +11 -0
  101. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  102. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  103. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  104. data/test/dummy/config/initializers/inflections.rb +16 -0
  105. data/test/dummy/config/initializers/mime_types.rb +4 -0
  106. data/test/dummy/config/initializers/new_framework_defaults.rb +21 -0
  107. data/test/dummy/config/initializers/session_store.rb +3 -0
  108. data/test/dummy/config/initializers/workarea.rb +5 -0
  109. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  110. data/test/dummy/config/locales/en.yml +23 -0
  111. data/test/dummy/config/puma.rb +47 -0
  112. data/test/dummy/config/routes.rb +5 -0
  113. data/test/dummy/config/secrets.yml +38 -0
  114. data/test/dummy/config/spring.rb +6 -0
  115. data/test/dummy/config.ru +5 -0
  116. data/test/dummy/db/seeds.rb +2 -0
  117. data/test/dummy/public/404.html +67 -0
  118. data/test/dummy/public/422.html +67 -0
  119. data/test/dummy/public/500.html +66 -0
  120. data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
  121. data/test/dummy/public/apple-touch-icon.png +0 -0
  122. data/test/dummy/public/favicon.ico +0 -0
  123. data/test/factories/workarea/factories/listrak.rb +15 -0
  124. data/test/helpers/workarea/listrak/analytics/helper_test.rb +38 -0
  125. data/test/integration/workarea/admin/listrak/configuration_integration_test.rb +26 -0
  126. data/test/integration/workarea/admin/listrak/events_integration_test.rb +21 -0
  127. data/test/lib/generators/workarea/listrak/message_generator_test.rb +26 -0
  128. data/test/queries/workarea/categorization_test.decorator +15 -0
  129. data/test/services/workarea/listrak/data_api/customers_test.rb +35 -0
  130. data/test/services/workarea/listrak/data_api/orders_test.rb +24 -0
  131. data/test/services/workarea/listrak/data_api/products_test.rb +27 -0
  132. data/test/services/workarea/listrak/email_api/contacts_test.rb +55 -0
  133. data/test/services/workarea/listrak/email_api/events_test.rb +51 -0
  134. data/test/services/workarea/listrak/email_api/lists_test.rb +45 -0
  135. data/test/services/workarea/listrak/email_api/messages_test.rb +28 -0
  136. data/test/services/workarea/listrak/email_api/transactional_messages_test.rb +50 -0
  137. data/test/services/workarea/listrak/oauth_test.rb +27 -0
  138. data/test/services/workarea/listrak/transactional_message_test.rb +48 -0
  139. data/test/support/workarea/listrak/test_order_confirmation_email.rb +116 -0
  140. data/test/support/workarea/listrak/vcr_config.rb +31 -0
  141. data/test/system/workarea/listrak_system_test.rb +75 -0
  142. data/test/test_helper.rb +16 -0
  143. data/test/vcr_cassettes/listrak/data_api/customers_import-successful.yml +88 -0
  144. data/test/vcr_cassettes/listrak/data_api/orders_import-successful.yml +90 -0
  145. data/test/vcr_cassettes/listrak/data_api/products_import-successful.yml +88 -0
  146. data/test/vcr_cassettes/listrak/email_api/contacts_get-successful.yml +87 -0
  147. data/test/vcr_cassettes/listrak/email_api/contacts_upsert-already_unsubscribed.yml +90 -0
  148. data/test/vcr_cassettes/listrak/email_api/contacts_upsert-successful.yml +87 -0
  149. data/test/vcr_cassettes/listrak/email_api/events_create-invalid_parameter.yml +90 -0
  150. data/test/vcr_cassettes/listrak/email_api/events_create-successful.yml +87 -0
  151. data/test/vcr_cassettes/listrak/email_api/events_get-successful.yml +88 -0
  152. data/test/vcr_cassettes/listrak/email_api/lists_all-successful.yml +88 -0
  153. data/test/vcr_cassettes/listrak/email_api/messages_create-successful.yml +88 -0
  154. data/test/vcr_cassettes/listrak/email_api/transactional_messages_create-successful.yml +89 -0
  155. data/test/vcr_cassettes/listrak/oauth-successful.yml +44 -0
  156. data/test/vcr_cassettes/listrak/oauth-unsuccessful.yml +46 -0
  157. data/test/vcr_cassettes/listrak/system_tests/footer_email_signup-successful.yml +171 -0
  158. data/test/vcr_cassettes/listrak/system_tests/footer_email_signup_overrides_unsubscribe.yml +255 -0
  159. data/test/vcr_cassettes/listrak/system_tests/unsubscribing.yml +593 -0
  160. data/test/workers/workarea/listrak/order_exporter_test.rb +31 -0
  161. data/test/workers/workarea/listrak/product_exporter_test.rb +62 -0
  162. data/workarea-listrak.gemspec +16 -0
  163. metadata +223 -0
@@ -0,0 +1,197 @@
1
+ module Workarea
2
+ module Listrak
3
+ module Models
4
+ class OrderItem
5
+
6
+ attr_reader :order, :order_item
7
+
8
+ def initialize(order, order_item)
9
+ @order = order
10
+ @order_item = order_item
11
+ end
12
+
13
+ def as_json
14
+ {
15
+ discountDescription: discount_description,
16
+ discountType: discount_type,
17
+ discountedPrice: discount_price,
18
+ itemTotal: item_total,
19
+ itemDiscountTotal: item_discount_total,
20
+ meta1: meta1,
21
+ meta2: meta2,
22
+ meta3: meta3,
23
+ meta4: meta4,
24
+ meta5: meta5,
25
+ orderNumber: order_number,
26
+ price: price,
27
+ quantity: quantity,
28
+ shipDate: ship_date,
29
+ shippingMethod: shipping_method,
30
+ sku: sku,
31
+ status: status,
32
+ trackingNumber: tracking_number
33
+ }
34
+ end
35
+
36
+ # Description of the discount for the line item
37
+ #
38
+ # @return [String]
39
+ #
40
+ def discount_description
41
+ end
42
+
43
+ # Type of discount for the line item
44
+ #
45
+ # "NotSet" "PriceOverride" "PriceRule" "Promotion" "SeniorCitizen" "Markdown" "Coupon" "QuantityDiscount" "Rebate" "CashDiscount" "TradeDiscount" "TradeInKind" "PromptPaymentDiscount" "GeneralDiscount" "GiftVoucher" "FlexibleDiscount" "RewardProgram" "ManufacturerReward" "CreditCardReward"
46
+ #
47
+ # @return [String]
48
+ #
49
+ def discount_type
50
+ end
51
+
52
+ # Total discounted cost of product
53
+ #
54
+ # @return [Float]
55
+ #
56
+ def discount_price
57
+ order_item.price_adjustments
58
+ .select { |pa| pa.data['discount_value'].present? && pa.price == 'item' }
59
+ .sum { |d| d.data['discount_value'] }
60
+ .abs
61
+ end
62
+
63
+ # Total line item cost (quantity times price)
64
+ #
65
+ # @return [Float]
66
+ #
67
+ def item_total
68
+ order_item.total_value.to_f
69
+ end
70
+
71
+ # Total amount of the discount for the line item
72
+ #
73
+ # @return [Float]
74
+ #
75
+ def item_discount_total
76
+ order_item.price_adjustments
77
+ .select { |pa| pa.data['discount_value'].present? && pa.price == 'item' }
78
+ .sum { |d| d.data['discount_value'] }
79
+ .abs
80
+ end
81
+
82
+ # Additional Optional Information
83
+ #
84
+ # limited to 500 characters
85
+ #
86
+ # @return [String]
87
+ #
88
+ def meta1
89
+ end
90
+
91
+ # Additional Optional Information
92
+ #
93
+ # limited to 500 characters
94
+ #
95
+ # @return [String]
96
+ #
97
+ def meta2
98
+ end
99
+
100
+ # Additional Optional Information
101
+ #
102
+ # limited to 500 characters
103
+ #
104
+ # @return [String]
105
+ #
106
+ def meta3
107
+ end
108
+
109
+ # Additional Optional Information
110
+ #
111
+ # limited to 500 characters
112
+ #
113
+ # @return [String]
114
+ #
115
+ def meta4
116
+ end
117
+
118
+ # Additional Optional Information
119
+ #
120
+ # limited to 500 characters
121
+ #
122
+ # @return [String]
123
+ #
124
+ def meta5
125
+ end
126
+
127
+ # Order number
128
+ #
129
+ # limited to 50 characters
130
+ #
131
+ # @return [String]
132
+ #
133
+ def order_number
134
+ order.id.to_s
135
+ end
136
+
137
+ # Price of one unit purchased
138
+ #
139
+ # @return [Float]
140
+ #
141
+ def price
142
+ order_item.original_unit_price.to_f
143
+ end
144
+
145
+ # Total number of units purchased
146
+ #
147
+ # return [Integer]
148
+ #
149
+ def quantity
150
+ order_item.quantity
151
+ end
152
+
153
+ # Timestamp when item shipped (ET)
154
+ #
155
+ # @return [String] DateTime in %FT%TZ
156
+ #
157
+ def ship_date
158
+ end
159
+
160
+ # Shipping method (e.g. UPS Ground)
161
+ #
162
+ # limited to 32 characters
163
+ #
164
+ # @return [String]
165
+ #
166
+ def shipping_method
167
+ end
168
+
169
+ # Unique stock number of product
170
+ #
171
+ # limited to 100 characters
172
+ #
173
+ # @return [String]
174
+ #
175
+ def sku
176
+ order_item.sku
177
+ end
178
+
179
+ # Status indicator
180
+ #
181
+ # "NotSet" "Misc" "PreOrder" "BackOrder" "Pending" "Hold" "Processing" "Shipped" "Completed" "Returned" "Canceled" "Unknown" "Closed"
182
+ #
183
+ # @return [String]
184
+ #
185
+ def status
186
+ end
187
+
188
+ # Shipment tracking number
189
+ #
190
+ # limited to 32 characters
191
+ #
192
+ def tracking_number
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,369 @@
1
+ module Workarea
2
+ module Listrak
3
+ module Models
4
+ class ProductForm
5
+ include ActionView::Helpers::AssetUrlHelper
6
+ include Workarea::I18n::DefaultUrlOptions
7
+ include Workarea::ApplicationHelper
8
+ include Storefront::Engine.routes.url_helpers
9
+
10
+
11
+ # @param [Workarea::Catalog::Product] product
12
+ # @param [String] sku
13
+ def initialize(product, sku, pricing_sku: nil, inventory_sku: nil)
14
+ @product = product
15
+ @sku = sku
16
+ @pricing_sku = pricing_sku
17
+ @inventory_sku = inventory_sku
18
+ end
19
+
20
+ def as_json(_options)
21
+ {
22
+ brand: brand,
23
+ category: category,
24
+ color: color,
25
+ description: description,
26
+ discontinued: discontinued,
27
+ gender: gender,
28
+ imageUrl: image_url,
29
+ inStock: in_stock,
30
+ isClearance: is_clearence,
31
+ isOutlet: is_outlet,
32
+ isPurchasable: is_purchasable,
33
+ isViewable: is_viewable,
34
+ linkUrl: link_url,
35
+ masterSku: master_sku,
36
+ meta1: meta1,
37
+ meta2: meta2,
38
+ meta3: meta3,
39
+ meta4: meta4,
40
+ meta5: meta5,
41
+ msrp: msrp,
42
+ onSale: on_sale,
43
+ price: price,
44
+ qoh: quantity_on_hand,
45
+ saleEndDate: sale_end_date,
46
+ salePrice: sale_price,
47
+ saleStartDate: sale_start_date,
48
+ size: size,
49
+ sku: sku,
50
+ style: style,
51
+ subCategory: sub_category,
52
+ title: title,
53
+ unitCost: unit_cost
54
+ }.compact
55
+ end
56
+
57
+ # Brand name of product
58
+ #
59
+ # limited to 50 characters
60
+ #
61
+ # @return [String]
62
+ #
63
+ def brand
64
+ product.try(:brand)
65
+ end
66
+
67
+ # Category or department
68
+ #
69
+ # limited to 50 characters
70
+ #
71
+ # @return [String]
72
+ #
73
+ def category
74
+ categorization.default_model.try(:name)
75
+ end
76
+
77
+ # Color of product (e.g. green, paisley, etc.)
78
+ #
79
+ # limited to 100 characters
80
+ #
81
+ # @return [String]
82
+ #
83
+ def color
84
+ variant.fetch_detail('color')
85
+ end
86
+
87
+ # Description of product
88
+ #
89
+ # limited to 4000 characters
90
+ #
91
+ # @return [String]
92
+ #
93
+ def description
94
+ product.description
95
+ end
96
+
97
+ # Explicit indicator that the item has been discontinued
98
+ #
99
+ # @return [Boolean]
100
+ #
101
+ def discontinued
102
+ end
103
+
104
+ # Gender of product (if applicable)
105
+ #
106
+ # limited to 50 characters
107
+ #
108
+ # @return [String]
109
+ #
110
+ def gender
111
+ end
112
+
113
+ # URL for product image
114
+ #
115
+ # limited to 500 characters
116
+ #
117
+ # @return [String]
118
+ #
119
+ def image_url
120
+ return unless image = variant_image || product.images.first
121
+ @image_url ||= product_image_url(image, :detail)
122
+ end
123
+
124
+ # Explicit indicator that the item is in stock
125
+ #
126
+ # @return [Boolean]
127
+ #
128
+ def in_stock
129
+ quantity_on_hand > 0
130
+ end
131
+
132
+ # Explicit indicator that the item is a clearance item
133
+ #
134
+ # @return [Boolean]
135
+ #
136
+ def is_clearence
137
+ end
138
+
139
+ # Explicit indicator that the item is an outlet item
140
+ #
141
+ # @return [Boolean]
142
+ #
143
+ def is_outlet
144
+ end
145
+
146
+ # Explicit indicator that the item can be included in recommendations
147
+ #
148
+ # @return [Boolean]
149
+ #
150
+ def is_purchasable
151
+ product.purchasable? && inventory_sku.purchasable?
152
+ end
153
+
154
+ # Flag used in some systems to determine if the item should be included in recommendations
155
+ #
156
+ # @return [Boolean]
157
+ #
158
+ def is_viewable
159
+ product.purchasable? && inventory_sku.purchasable?
160
+ end
161
+
162
+ # URL for product webpage
163
+ #
164
+ # limited to 500 characters
165
+ #
166
+ # @return [String]
167
+ #
168
+ def link_url
169
+ product_url(product, host: Workarea.config.host)
170
+ end
171
+
172
+ # Unique stock number of the master product
173
+ #
174
+ # limited to 100 characters
175
+ #
176
+ # @return [String]
177
+ #
178
+ def master_sku
179
+ product.id.to_s
180
+ end
181
+
182
+ # Additional meta imformation
183
+ #
184
+ # limted to 500 characters
185
+ #
186
+ # @return [String]
187
+ #
188
+ def meta1
189
+ end
190
+
191
+ # Additional meta imformation
192
+ #
193
+ # limted to 500 characters
194
+ #
195
+ # @return [String]
196
+ #
197
+ def meta2
198
+ end
199
+
200
+ # Additional meta imformation
201
+ #
202
+ # limted to 500 characters
203
+ #
204
+ # @return [String]
205
+ #
206
+ def meta3
207
+ end
208
+
209
+ # Additional meta imformation
210
+ #
211
+ # limted to 500 characters
212
+ #
213
+ # @return [String]
214
+ #
215
+ def meta4
216
+ end
217
+
218
+ # Additional meta imformation
219
+ #
220
+ # limted to 500 characters
221
+ #
222
+ # @return [String]
223
+ #
224
+ def meta5
225
+ end
226
+
227
+ # Retail price of the product
228
+ #
229
+ # @return [Float]
230
+ #
231
+ def msrp
232
+ end
233
+
234
+ # Explicit indicator that the item is on sale
235
+ #
236
+ # @return [Boolean
237
+ #
238
+ def on_sale
239
+ pricing_sku.on_sale?
240
+ end
241
+
242
+ # List price of product
243
+ #
244
+ # @return [Float]
245
+ #
246
+ def price
247
+ pricing_sku.find_price.sell.to_f
248
+ end
249
+
250
+ # Quantity on hand
251
+ #
252
+ # return [Integer]
253
+ #
254
+ def quantity_on_hand
255
+ inventory_sku.available
256
+ end
257
+
258
+ # End date time of sale
259
+ #
260
+ # @return [String] sale_end_date DateTime in %FT%TZ
261
+ #
262
+ def sale_end_date
263
+ end
264
+
265
+ # Sale price of product
266
+ #
267
+ # @return [Float
268
+ #
269
+ def sale_price
270
+ pricing_sku.find_price.sale.to_f
271
+ end
272
+
273
+ # Start date time of sale
274
+ #
275
+ # @return [String] sale_start_date DateTime in %FT%TZ
276
+ #
277
+ def sale_start_date
278
+ end
279
+
280
+ # Size of product (e.g. small, M, 6 7/8”)
281
+ #
282
+ # limited to 50 characters
283
+ #
284
+ # @return [String]
285
+ #
286
+ def size
287
+ variant.fetch_detail('size')
288
+ end
289
+
290
+ # Unique stock number of product
291
+ #
292
+ # limited to 100 characters
293
+ #
294
+ # @return [String]
295
+ #
296
+ def sku
297
+ @sku
298
+ end
299
+
300
+ # Style of product
301
+ #
302
+ # limited to 100 characters
303
+ #
304
+ # @return [String]
305
+ #
306
+ def style
307
+ end
308
+
309
+ # Sub-category or sub-department
310
+ #
311
+ # limited to 50 characters
312
+ #
313
+ # @return [String]
314
+ #
315
+ def sub_category
316
+ categorization.secondary_model.try(:name)
317
+ end
318
+
319
+ # Product name
320
+ #
321
+ # limited to 500 characters
322
+ #
323
+ # @return [String]
324
+ #
325
+ def title
326
+ product.name
327
+ end
328
+
329
+ # Price per individual item
330
+ #
331
+ # @return [Float]
332
+ #
333
+ def unit_cost
334
+ end
335
+
336
+ private
337
+
338
+ attr_reader :product
339
+
340
+ def categorization
341
+ @categorization ||= Categorization.new(product)
342
+ end
343
+
344
+ def variant
345
+ @variant ||= product.variants.find_by(sku: sku)
346
+ end
347
+
348
+ def pricing_sku
349
+ @pricing_sku ||= Pricing::Sku.find sku
350
+ end
351
+
352
+ def inventory_sku
353
+ @inventory_sku ||= Inventory::Sku.find sku
354
+ end
355
+
356
+ def variant_image
357
+ @variant_image ||=
358
+ begin
359
+ sku_options = variant.details.values.flat_map { |options| options.map(&:optionize) }
360
+
361
+ product.images.detect do |image|
362
+ sku_options.include?(image.option.optionize)
363
+ end
364
+ end
365
+ end
366
+ end
367
+ end
368
+ end
369
+ end
@@ -0,0 +1,21 @@
1
+ module Workarea
2
+ module Listrak
3
+ module Models
4
+ class TransactionalMessageForm
5
+ attr_reader :email_address, :segmentation_field_values
6
+
7
+ def initialize(email_address:, segmentation_field_values: [])
8
+ @email_address = email_address
9
+ @segmentation_field_values = segmentation_field_values
10
+ end
11
+
12
+ def to_json
13
+ {
14
+ emailAddress: email_address,
15
+ segmentationFieldValues: segmentation_field_values
16
+ }.compact.to_json
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,45 @@
1
+ module Workarea
2
+ module Listrak
3
+ module Oauth
4
+ # Generates an oauth token for a client_id and client_secret.
5
+ #
6
+ # @param client_id [String] client id
7
+ # @param client_secret [String] client secret
8
+ # @param options [Hash] extra options when getting the OAuth token
9
+ # @option options [Integer] timeout value for open and read timeouts
10
+ # @option options [Integer] open_timeout value for open timeout
11
+ # @option options [Integer] read_timeout value for read timeout
12
+ #
13
+ # @raise [OauthError] raised if generating an Oauth token is unsucessful
14
+ #
15
+ # @return [String] Oauth token
16
+ def self.token(client_id:, client_secret:, **options)
17
+ cache_key = "listrak/api/#{client_id}"
18
+ token = Rails.cache.read(cache_key)
19
+
20
+ return token if token.present?
21
+
22
+ uri = URI('https://auth.listrak.com/OAuth2/Token')
23
+ params = {
24
+ grant_type: 'client_credentials',
25
+ client_id: client_id,
26
+ client_secret: client_secret
27
+ }
28
+
29
+ response = Net::HTTP.post_form uri, params
30
+
31
+ case response
32
+ when ::Net::HTTPSuccess
33
+ body = JSON.parse response.body
34
+ token = body["access_token"]
35
+ expiry = body["expires_in"] - 60
36
+
37
+ Rails.cache.write(cache_key, token, expires_in: expiry)
38
+ token
39
+ else
40
+ raise OauthError.new response
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,83 @@
1
+ module Workarea
2
+ module Listrak
3
+ # Base functionality for Listrak message sender classes.
4
+ # +Listrak::TransactionalMessage+ objects wrap a call to the
5
+ # Listrak REST API and allow the user to cleanly define
6
+ # attribute ID / value pairs and "name" them by defining
7
+ # attribute values as method calls.
8
+ #
9
+ # @example
10
+ # module Workarea
11
+ # class OrderConfirmationMessage
12
+ # include Listrak::TransactionalMessage
13
+ #
14
+ # message_id 12345
15
+ # message_attributes name: 67890
16
+ #
17
+ # def initialize(model)
18
+ # @model = model
19
+ # end
20
+ #
21
+ # def name
22
+ # @model.class.name
23
+ # end
24
+ #
25
+ # private
26
+ #
27
+ # def email_address
28
+ # model.email_address
29
+ # end
30
+ # end
31
+ # end
32
+ module TransactionalMessage
33
+ extend ActiveSupport::Concern
34
+
35
+ included do
36
+ class_attribute :listrak_message_id
37
+ class_attribute :transactional_attributes
38
+ end
39
+
40
+ class_methods do
41
+ def message_id(id)
42
+ self.listrak_message_id = id
43
+ end
44
+
45
+ def message_attributes(attributes)
46
+ self.transactional_attributes = attributes.symbolize_keys
47
+ end
48
+ end
49
+
50
+ # @abstract Subclass is expected to implement #email_address
51
+ # @!method email_address
52
+ # Email address to deliver this message to
53
+
54
+ # Sends the transactional mesasge
55
+ #
56
+ # @return [nil]
57
+ #
58
+ def deliver
59
+ transactional_message_form = Listrak::Models::TransactionalMessageForm.new(
60
+ email_address: email_address,
61
+ segmentation_field_values: segmentation_field_values
62
+ )
63
+
64
+ Listrak.email.transactional_messages.create(
65
+ Listrak.configuration.default_list_id,
66
+ listrak_message_id,
67
+ transactional_message_form
68
+ )
69
+ nil
70
+ end
71
+
72
+ private
73
+
74
+ # @return [Array<Hash>]
75
+ #
76
+ def segmentation_field_values
77
+ transactional_attributes.map do |name, id|
78
+ { segmentationFieldId: id, value: send(name).to_s }
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end