workarea-core 3.4.44 → 3.5.0.beta.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 (427) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +52 -0
  3. data/app/assets/javascripts/workarea/core/modules/duplicate_id.js +1 -5
  4. data/app/assets/javascripts/workarea/core/modules/style_guide_autocomplete_fields.js +9 -42
  5. data/app/assets/javascripts/workarea/core/modules/url.js +14 -0
  6. data/app/controllers/workarea/application_controller.rb +5 -1
  7. data/app/controllers/workarea/authentication.rb +15 -26
  8. data/app/controllers/workarea/authorization.rb +3 -3
  9. data/app/controllers/workarea/current_referrer.rb +1 -2
  10. data/app/controllers/workarea/current_release.rb +1 -1
  11. data/app/controllers/workarea/current_segments.rb +52 -0
  12. data/app/controllers/workarea/current_tracking.rb +45 -0
  13. data/app/controllers/workarea/http_caching.rb +30 -0
  14. data/app/controllers/workarea/impersonation.rb +18 -44
  15. data/app/helpers/workarea/schema_org_helper.rb +21 -0
  16. data/app/mailers/workarea/application_mailer.rb +2 -4
  17. data/app/middleware/workarea/application_middleware.rb +44 -0
  18. data/app/middleware/workarea/query_cache_middleware.rb +55 -0
  19. data/app/middleware/workarea/release_server_middleware.rb +1 -1
  20. data/app/models/workarea/application_document.rb +1 -1
  21. data/app/models/workarea/bulk_action/product_edit.rb +6 -6
  22. data/app/models/workarea/calculate_percent_change.rb +1 -1
  23. data/app/models/workarea/catalog/category.rb +0 -2
  24. data/app/models/workarea/catalog/product.rb +19 -2
  25. data/app/models/workarea/checkout.rb +18 -6
  26. data/app/models/workarea/checkout/collect_payment.rb +10 -1
  27. data/app/models/workarea/checkout/fraud/analyzer.rb +44 -0
  28. data/app/models/workarea/checkout/fraud/no_decision_analyzer.rb +14 -0
  29. data/app/models/workarea/checkout/fraud/test_analyzer.rb +26 -0
  30. data/app/models/workarea/configuration/admin.rb +25 -0
  31. data/app/models/workarea/configuration/params.rb +45 -0
  32. data/app/models/workarea/content.rb +12 -82
  33. data/app/models/workarea/content/asset.rb +5 -18
  34. data/app/models/workarea/content/block.rb +8 -2
  35. data/app/models/workarea/content/block_draft.rb +7 -2
  36. data/app/models/workarea/content/block_type.rb +2 -2
  37. data/app/models/workarea/content/block_type_definition.rb +4 -0
  38. data/app/models/workarea/content/preset.rb +1 -1
  39. data/app/models/workarea/data_file/csv.rb +6 -8
  40. data/app/models/workarea/data_file/import.rb +9 -1
  41. data/app/models/workarea/data_file/json.rb +1 -20
  42. data/app/models/workarea/data_file/operation.rb +0 -4
  43. data/app/models/workarea/data_file/tax_rates.rb +3 -0
  44. data/app/models/workarea/featured_products.rb +8 -0
  45. data/app/models/workarea/fulfillment/policies/base.rb +21 -0
  46. data/app/models/workarea/fulfillment/policies/download.rb +21 -0
  47. data/app/models/workarea/fulfillment/policies/ignore.rb +11 -0
  48. data/app/models/workarea/fulfillment/policies/ship.rb +15 -0
  49. data/app/models/workarea/fulfillment/sku.rb +72 -0
  50. data/app/models/workarea/fulfillment/token.rb +36 -0
  51. data/app/models/workarea/inquiry.rb +1 -2
  52. data/app/models/workarea/insights/customer_acquisition.rb +5 -9
  53. data/app/models/workarea/insights/trending_products.rb +2 -2
  54. data/app/models/workarea/insights/trending_searches.rb +2 -2
  55. data/app/models/workarea/inventory/collection.rb +30 -0
  56. data/app/models/workarea/inventory/collection_status.rb +40 -0
  57. data/app/models/workarea/metrics/affinity.rb +33 -0
  58. data/app/models/workarea/metrics/country_by_day.rb +4 -0
  59. data/app/models/workarea/metrics/product_by_day.rb +3 -0
  60. data/app/models/workarea/metrics/product_by_week.rb +2 -0
  61. data/app/models/workarea/metrics/product_for_last_week.rb +8 -12
  62. data/app/models/workarea/metrics/sales_by_day.rb +5 -0
  63. data/app/models/workarea/metrics/search_by_day.rb +1 -3
  64. data/app/models/workarea/metrics/search_for_last_week.rb +5 -11
  65. data/app/models/workarea/metrics/segment_by_day.rb +31 -0
  66. data/app/models/workarea/metrics/sku_by_day.rb +3 -0
  67. data/app/models/workarea/metrics/tender_by_day.rb +11 -0
  68. data/app/models/workarea/metrics/update_user_aggregations.rb +77 -0
  69. data/app/models/workarea/metrics/user.rb +73 -87
  70. data/app/models/workarea/navigation/breadcrumbs.rb +10 -1
  71. data/app/models/workarea/order.rb +47 -4
  72. data/app/models/workarea/order/fraud_decision.rb +18 -0
  73. data/app/models/workarea/order/item.rb +5 -0
  74. data/app/models/workarea/order/queries.rb +1 -0
  75. data/app/models/workarea/order/status.rb +10 -1
  76. data/app/models/workarea/payment.rb +7 -2
  77. data/app/models/workarea/payment/credit_card.rb +12 -0
  78. data/app/models/workarea/pricing/cache_key.rb +9 -3
  79. data/app/models/workarea/pricing/calculator.rb +5 -1
  80. data/app/models/workarea/pricing/calculators/tax_calculator.rb +32 -5
  81. data/app/models/workarea/pricing/discount.rb +2 -3
  82. data/app/models/workarea/pricing/discount/application_group.rb +8 -3
  83. data/app/models/workarea/pricing/discount/free_gift.rb +2 -1
  84. data/app/models/workarea/pricing/discount/redemption.rb +1 -1
  85. data/app/models/workarea/pricing/item_tax_applier.rb +41 -0
  86. data/app/models/workarea/pricing/price.rb +1 -0
  87. data/app/models/workarea/pricing/request.rb +11 -0
  88. data/app/models/workarea/pricing/sku.rb +1 -0
  89. data/app/models/workarea/pricing/tax_application.rb +21 -0
  90. data/app/models/workarea/pricing/tax_applier.rb +12 -15
  91. data/app/models/workarea/pricing/unsupported_segmentation.rb +22 -0
  92. data/app/models/workarea/product_rule.rb +5 -0
  93. data/app/models/workarea/releasable.rb +83 -89
  94. data/app/models/workarea/release.rb +72 -99
  95. data/app/models/workarea/release/activation.rb +45 -0
  96. data/app/models/workarea/release/changes.rb +45 -0
  97. data/app/models/workarea/release/changeset.rb +42 -52
  98. data/app/models/workarea/release/preview.rb +28 -0
  99. data/app/models/workarea/release/status.rb +2 -24
  100. data/app/models/workarea/release_session.rb +11 -11
  101. data/app/models/workarea/search/admin.rb +17 -39
  102. data/app/models/workarea/search/admin/catalog_product.rb +1 -2
  103. data/app/models/workarea/search/admin/fulfillment_sku.rb +27 -0
  104. data/app/models/workarea/search/admin/order.rb +1 -1
  105. data/app/models/workarea/search/admin/pricing_discount.rb +1 -1
  106. data/app/models/workarea/search/admin/release.rb +1 -4
  107. data/app/models/workarea/search/admin/segment.rb +19 -0
  108. data/app/models/workarea/search/order_text.rb +23 -6
  109. data/app/models/workarea/search/storefront.rb +33 -29
  110. data/app/models/workarea/search/storefront/category_query.rb +152 -0
  111. data/app/models/workarea/search/storefront/product/categories.rb +11 -45
  112. data/app/models/workarea/segment.rb +54 -0
  113. data/app/models/workarea/segment/first_time_customer.rb +8 -0
  114. data/app/models/workarea/segment/first_time_visitor.rb +12 -0
  115. data/app/models/workarea/segment/life_cycle.rb +44 -0
  116. data/app/models/workarea/segment/loyal_customer.rb +12 -0
  117. data/app/models/workarea/segment/returning_customer.rb +14 -0
  118. data/app/models/workarea/segment/returning_visitor.rb +12 -0
  119. data/app/models/workarea/segment/rules/base.rb +16 -0
  120. data/app/models/workarea/segment/rules/browser_info.rb +29 -0
  121. data/app/models/workarea/segment/rules/geolocation.rb +29 -0
  122. data/app/models/workarea/segment/rules/geolocation_option.rb +53 -0
  123. data/app/models/workarea/segment/rules/last_order.rb +14 -0
  124. data/app/models/workarea/segment/rules/logged_in.rb +13 -0
  125. data/app/models/workarea/segment/rules/orders.rb +17 -0
  126. data/app/models/workarea/segment/rules/revenue.rb +17 -0
  127. data/app/models/workarea/segment/rules/sessions.rb +17 -0
  128. data/app/models/workarea/segment/rules/tags.rb +14 -0
  129. data/app/models/workarea/segment/rules/traffic_referrer.rb +18 -0
  130. data/app/models/workarea/segmentable.rb +66 -0
  131. data/app/models/workarea/sort.rb +14 -2
  132. data/app/models/workarea/tax/rate.rb +35 -1
  133. data/app/models/workarea/user/authorization.rb +19 -13
  134. data/app/models/workarea/user/login.rb +4 -0
  135. data/app/models/workarea/user/password_reset.rb +1 -3
  136. data/app/queries/workarea/categorization.rb +3 -3
  137. data/app/queries/workarea/featured_categorization.rb +53 -0
  138. data/app/queries/workarea/order_cancellation_metrics.rb +155 -0
  139. data/app/queries/workarea/order_item_details.rb +16 -3
  140. data/app/queries/workarea/order_metrics.rb +32 -3
  141. data/app/queries/workarea/product_primary_navigation.rb +13 -2
  142. data/app/queries/workarea/product_releases.rb +38 -0
  143. data/app/queries/workarea/recommendation/user_activity_based.rb +14 -6
  144. data/app/queries/workarea/reports/average_order_value.rb +1 -1
  145. data/app/queries/workarea/reports/customers.rb +14 -11
  146. data/app/queries/workarea/reports/first_time_vs_returning_sales.rb +1 -1
  147. data/app/queries/workarea/reports/group_by_time.rb +13 -17
  148. data/app/queries/workarea/reports/sales_by_category.rb +1 -1
  149. data/app/queries/workarea/reports/sales_by_country.rb +10 -3
  150. data/app/queries/workarea/reports/sales_by_discount.rb +1 -1
  151. data/app/queries/workarea/reports/sales_by_menu.rb +1 -1
  152. data/app/queries/workarea/reports/sales_by_product.rb +39 -4
  153. data/app/queries/workarea/reports/sales_by_sku.rb +39 -4
  154. data/app/queries/workarea/reports/sales_by_tender.rb +42 -0
  155. data/app/queries/workarea/reports/sales_by_traffic_referrer.rb +1 -1
  156. data/app/queries/workarea/reports/sales_over_time.rb +10 -3
  157. data/app/queries/workarea/reports/searches.rb +1 -1
  158. data/app/queries/workarea/reports/searches_over_time.rb +1 -1
  159. data/app/queries/workarea/reports/searches_without_results_over_time.rb +1 -1
  160. data/app/queries/workarea/search/admin_fulfillment_skus.rb +20 -0
  161. data/app/queries/workarea/search/admin_releases.rb +1 -4
  162. data/app/queries/workarea/search/admin_search.rb +0 -4
  163. data/app/queries/workarea/search/admin_segments.rb +16 -0
  164. data/app/queries/workarea/search/admin_sorting.rb +1 -1
  165. data/app/queries/workarea/search/pagination.rb +1 -4
  166. data/app/queries/workarea/search/product_display_rules.rb +40 -8
  167. data/app/queries/workarea/search/product_entries.rb +15 -1
  168. data/app/queries/workarea/search/product_search.rb +4 -1
  169. data/app/queries/workarea/search/storefront_search.rb +5 -4
  170. data/app/queries/workarea/search/storefront_search/exact_matches.rb +1 -1
  171. data/app/queries/workarea/search/storefront_search/response.rb +6 -4
  172. data/app/seeds/workarea/assets_seeds.rb +2 -1
  173. data/app/seeds/workarea/insights_seeds.rb +0 -23
  174. data/app/seeds/workarea/orders_seeds.rb +7 -6
  175. data/app/seeds/workarea/products_seeds.rb +2 -0
  176. data/app/seeds/workarea/segments_seeds.rb +8 -0
  177. data/app/seeds/workarea/tax_seeds.rb +3 -3
  178. data/app/services/workarea/cancel_order.rb +8 -3
  179. data/app/services/workarea/copy_order.rb +6 -0
  180. data/app/services/workarea/create_fulfillment.rb +5 -3
  181. data/app/services/workarea/direct_upload.rb +11 -19
  182. data/app/services/workarea/hash_update.rb +1 -18
  183. data/app/services/workarea/packaging.rb +1 -1
  184. data/app/services/workarea/save_publishing.rb +5 -1
  185. data/app/workers/sidekiq/callbacks.rb +4 -52
  186. data/app/workers/sidekiq/callbacks_worker.rb +4 -6
  187. data/app/workers/workarea/bulk_index_admin.rb +2 -2
  188. data/app/workers/workarea/bulk_index_products.rb +6 -5
  189. data/app/workers/workarea/bulk_index_searches.rb +5 -5
  190. data/app/workers/workarea/deactivate_stale_discounts.rb +3 -3
  191. data/app/workers/workarea/generate_insights.rb +1 -1
  192. data/app/workers/workarea/index_admin_search.rb +1 -0
  193. data/app/workers/workarea/index_categorization.rb +4 -7
  194. data/app/workers/workarea/index_category.rb +2 -1
  195. data/app/workers/workarea/index_category_changes.rb +11 -6
  196. data/app/workers/workarea/index_fulfillment_changes.rb +2 -1
  197. data/app/workers/workarea/index_help.rb +2 -1
  198. data/app/workers/workarea/index_page.rb +2 -1
  199. data/app/workers/workarea/index_payment_transactions.rb +2 -1
  200. data/app/workers/workarea/index_product.rb +4 -4
  201. data/app/workers/workarea/index_product_children.rb +4 -3
  202. data/app/workers/workarea/index_product_rule.rb +3 -2
  203. data/app/workers/workarea/index_search_customizations.rb +3 -2
  204. data/app/workers/workarea/index_skus.rb +5 -6
  205. data/app/workers/workarea/keep_product_index_fresh.rb +3 -5
  206. data/app/workers/workarea/process_import.rb +3 -3
  207. data/app/workers/workarea/process_search_recommendations.rb +5 -9
  208. data/app/workers/workarea/publish_release.rb +1 -0
  209. data/app/workers/workarea/save_metrics.rb +116 -0
  210. data/app/workers/workarea/save_order_cancellation_metrics.rb +35 -0
  211. data/app/workers/workarea/save_order_metrics.rb +10 -74
  212. data/app/workers/workarea/status_reporter.rb +2 -4
  213. data/app/workers/workarea/synchronize_user_metrics.rb +17 -0
  214. data/app/workers/workarea/update_payment_profile_email.rb +22 -0
  215. data/app/workers/workarea/verify_scheduled_releases.rb +4 -11
  216. data/config/initializers/00_configuration.rb +185 -0
  217. data/config/initializers/02_assets.rb +1 -0
  218. data/config/initializers/05_scheduled_jobs.rb +0 -7
  219. data/config/initializers/10_rack_middleware.rb +2 -5
  220. data/config/initializers/11_payment.rb +4 -0
  221. data/config/initializers/13_rack_attack.rb +2 -4
  222. data/config/initializers/14_content_block_types.rb +16 -16
  223. data/config/initializers/15_endpoint_monitoring.rb +3 -6
  224. data/config/initializers/{21_premailer.rb → 24_premailer.rb} +1 -0
  225. data/config/initializers/{20_i18n_js.rb → 25_i18n_js.rb} +0 -0
  226. data/config/locales/en.yml +13 -24
  227. data/lib/generators/workarea/content_block_type/templates/initializer.rb +1 -1
  228. data/lib/generators/workarea/install/USAGE +0 -1
  229. data/lib/generators/workarea/install/install_generator.rb +0 -21
  230. data/lib/generators/workarea/install/templates/initializer.rb.erb +1 -1
  231. data/lib/tasks/insights.rake +1 -0
  232. data/lib/tasks/migrate.rake +106 -0
  233. data/lib/tasks/search.rake +17 -19
  234. data/lib/tasks/tests.rake +1 -1
  235. data/lib/workarea.rb +102 -3
  236. data/lib/workarea/cache.rb +6 -35
  237. data/lib/workarea/changelog.rake +2 -2
  238. data/lib/workarea/configuration.rb +121 -148
  239. data/lib/workarea/configuration/administrable/definition.rb +42 -0
  240. data/lib/workarea/configuration/administrable/field.rb +79 -0
  241. data/lib/workarea/configuration/administrable/fieldset.rb +44 -0
  242. data/lib/workarea/configuration/administrable_options.rb +24 -0
  243. data/lib/workarea/configuration/cache_store.rb +3 -1
  244. data/lib/workarea/configuration/content_blocks.rb +17 -0
  245. data/lib/workarea/configuration/mongoid.rb +1 -4
  246. data/lib/workarea/configuration/session.rb +36 -0
  247. data/lib/workarea/configuration/sidekiq.rb +3 -1
  248. data/lib/workarea/core.rb +15 -11
  249. data/lib/workarea/core/engine.rb +3 -58
  250. data/lib/workarea/elasticsearch/document.rb +8 -15
  251. data/lib/workarea/ext/freedom_patches/action_view_cache_helper.rb +4 -6
  252. data/lib/workarea/ext/freedom_patches/active_support_duration.rb +14 -0
  253. data/lib/workarea/ext/freedom_patches/money.rb +11 -0
  254. data/lib/workarea/ext/freedom_patches/premailer.rb +6 -0
  255. data/lib/workarea/ext/freedom_patches/string.rb +19 -4
  256. data/lib/workarea/ext/mongoid/find_ordered.rb +2 -2
  257. data/lib/workarea/ext/mongoid/lookup_hash.rb +30 -0
  258. data/lib/workarea/geolocation.rb +24 -6
  259. data/lib/workarea/routes_constraints/super_admin.rb +1 -1
  260. data/lib/workarea/version.rb +3 -4
  261. data/lib/workarea/visit.rb +92 -0
  262. data/lib/workarea/warnings.rb +95 -0
  263. data/test/dummy/config/initializers/session_store.rb +1 -1
  264. data/test/fixtures/tax_rates.csv +3 -3
  265. data/test/generators/workarea/content_block_type_generator_test.rb +1 -1
  266. data/test/generators/workarea/install_generator_test.rb +0 -13
  267. data/test/integration/workarea/authentication_test.rb +27 -4
  268. data/test/integration/workarea/authorization_test.rb +5 -0
  269. data/test/integration/workarea/cache_varies_integration_test.rb +21 -23
  270. data/test/integration/workarea/monitoring_integration_test.rb +5 -10
  271. data/test/javascripts/duplicate_id_spec.js +1 -7
  272. data/test/javascripts/fixtures/{duplicate_id_fail.html.haml → duplicate_id.html.haml} +0 -1
  273. data/test/javascripts/form_submitting_controls_spec.js +0 -1
  274. data/test/lib/workarea/asset_endpoints/favicons_test.rb +11 -13
  275. data/test/lib/workarea/configuration/administrable/definition_test.rb +71 -0
  276. data/test/lib/workarea/configuration/administrable/field_test.rb +128 -0
  277. data/test/lib/workarea/configuration/administrable/fieldset_test.rb +78 -0
  278. data/test/lib/workarea/configuration/configuration_test.rb +20 -0
  279. data/test/lib/workarea/elasticsearch/document_test.rb +0 -20
  280. data/test/lib/workarea/elasticsearch/query_cache_test.rb +7 -7
  281. data/test/lib/workarea/ext/freedom_patches/money_test.rb +11 -0
  282. data/test/lib/workarea/ext/mongoid/lookup_hash_test.rb +86 -0
  283. data/test/lib/workarea/geolocation_test.rb +20 -0
  284. data/test/mailers/workarea/application_mailer_test.rb +1 -11
  285. data/test/middleware/workarea/query_cache_middleware_test.rb +55 -0
  286. data/test/models/workarea/checkout/collect_payment_test.rb +14 -6
  287. data/test/models/workarea/checkout_test.rb +31 -57
  288. data/test/models/workarea/configuration/params_test.rb +37 -0
  289. data/test/models/workarea/data_file/csv_test.rb +8 -73
  290. data/test/models/workarea/data_file/import_test.rb +31 -0
  291. data/test/models/workarea/data_file/json_test.rb +6 -48
  292. data/test/models/workarea/data_file/tax_test.rb +3 -0
  293. data/test/models/workarea/fulfillment/policies/download_test.rb +39 -0
  294. data/test/models/workarea/fulfillment/sku_test.rb +54 -0
  295. data/test/models/workarea/insights/best_customers_test.rb +5 -2
  296. data/test/models/workarea/insights/best_full_price_customers_test.rb +5 -2
  297. data/test/models/workarea/insights/customer_acquisition_test.rb +1 -1
  298. data/test/models/workarea/insights/customers_at_risk_test.rb +1 -1
  299. data/test/models/workarea/insights/low_aov_customers_test.rb +1 -1
  300. data/test/models/workarea/inventory/collection_test.rb +75 -0
  301. data/test/models/workarea/metrics/affinity_test.rb +85 -0
  302. data/test/models/workarea/metrics/product_by_week_test.rb +27 -31
  303. data/test/models/workarea/metrics/search_by_day_test.rb +3 -0
  304. data/test/models/workarea/metrics/search_by_week_test.rb +27 -31
  305. data/test/models/workarea/metrics/update_user_aggregations_test.rb +62 -0
  306. data/test/models/workarea/metrics/user_test.rb +146 -63
  307. data/test/models/workarea/navigation/breadcrumbs_test.rb +12 -2
  308. data/test/models/workarea/order/queries_test.rb +2 -0
  309. data/test/models/workarea/order_test.rb +44 -0
  310. data/test/models/workarea/payment/address_test.rb +109 -111
  311. data/test/models/workarea/payment/credit_card_integration_test.rb +0 -52
  312. data/test/models/workarea/payment/credit_card_test.rb +5 -0
  313. data/test/models/workarea/pricing/cache_key_test.rb +7 -1
  314. data/test/models/workarea/pricing/calculators/tax_calculator_test.rb +41 -1
  315. data/test/models/workarea/pricing/discount/collection_test.rb +27 -29
  316. data/test/models/workarea/pricing/discount_test.rb +22 -24
  317. data/test/models/workarea/pricing/item_tax_applier_test.rb +83 -0
  318. data/test/models/workarea/pricing/price_test.rb +9 -0
  319. data/test/models/workarea/pricing/request_test.rb +13 -0
  320. data/test/models/workarea/pricing/sku_test.rb +9 -0
  321. data/test/models/workarea/releasable_active_test.rb +113 -0
  322. data/test/models/workarea/releasable_test.rb +69 -120
  323. data/test/models/workarea/release/changeset_test.rb +41 -0
  324. data/test/models/workarea/release_jobs_test.rb +52 -0
  325. data/test/models/workarea/release_previewing_test.rb +43 -0
  326. data/test/models/workarea/release_test.rb +59 -153
  327. data/test/models/workarea/search/admin/content_asset_test.rb +26 -28
  328. data/test/models/workarea/search/order_text_test.rb +35 -0
  329. data/test/models/workarea/search/storefront/category_query_test.rb +81 -0
  330. data/test/models/workarea/search/storefront/product/categories_test.rb +10 -70
  331. data/test/models/workarea/search/storefront/product_test.rb +10 -11
  332. data/test/models/workarea/search/storefront_test.rb +1 -13
  333. data/test/models/workarea/segment/life_cycle_test.rb +24 -0
  334. data/test/models/workarea/segment/rules/browser_info_test.rb +33 -0
  335. data/test/models/workarea/segment/rules/geolocation_option_test.rb +16 -0
  336. data/test/models/workarea/segment/rules/geolocation_test.rb +49 -0
  337. data/test/models/workarea/segment/rules/last_order_test.rb +32 -0
  338. data/test/models/workarea/segment/rules/logged_in_test.rb +25 -0
  339. data/test/models/workarea/segment/rules/orders_test.rb +59 -0
  340. data/test/models/workarea/segment/rules/revenue_test.rb +59 -0
  341. data/test/models/workarea/segment/rules/sessions_test.rb +26 -0
  342. data/test/models/workarea/segment/rules/tags_test.rb +27 -0
  343. data/test/models/workarea/segment/rules/traffic_referrer_test.rb +31 -0
  344. data/test/models/workarea/segment_test.rb +80 -0
  345. data/test/models/workarea/segmentable_test.rb +74 -0
  346. data/test/models/workarea/shipping/address_test.rb +109 -111
  347. data/test/models/workarea/shipping/sku_test.rb +8 -12
  348. data/test/models/workarea/user/password_reset_test.rb +4 -12
  349. data/test/models/workarea/user_test.rb +13 -10
  350. data/test/queries/workarea/admin_search_query_wrapper_test.rb +21 -25
  351. data/test/queries/workarea/categorization_test.rb +49 -0
  352. data/test/queries/workarea/featured_categorization_test.rb +66 -0
  353. data/test/queries/workarea/order_cancellation_metrics_test.rb +203 -0
  354. data/test/queries/workarea/order_item_details_test.rb +17 -0
  355. data/test/queries/workarea/order_metrics_test.rb +12 -0
  356. data/test/queries/workarea/product_releases_test.rb +56 -0
  357. data/test/queries/workarea/recommendation/searches_test.rb +3 -3
  358. data/test/queries/workarea/recommendation/user_activity_based_test.rb +4 -4
  359. data/test/queries/workarea/reports/customers_test.rb +12 -8
  360. data/test/queries/workarea/reports/report_test.rb +4 -6
  361. data/test/queries/workarea/reports/sales_by_country_test.rb +18 -3
  362. data/test/queries/workarea/reports/sales_by_product_test.rb +28 -8
  363. data/test/queries/workarea/reports/sales_by_sku_test.rb +28 -8
  364. data/test/queries/workarea/reports/sales_by_tender_test.rb +100 -0
  365. data/test/queries/workarea/reports/sales_by_traffic_referrer_test.rb +6 -6
  366. data/test/queries/workarea/search/admin_releases_test.rb +1 -26
  367. data/test/queries/workarea/search/admin_search_test.rb +0 -10
  368. data/test/queries/workarea/search/admin_users_test.rb +2 -2
  369. data/test/queries/workarea/search/category_browse_test.rb +53 -0
  370. data/test/queries/workarea/search/facet_sorting/size_test.rb +11 -13
  371. data/test/queries/workarea/search/pagination_test.rb +9 -26
  372. data/test/queries/workarea/search/product_entries_test.rb +27 -0
  373. data/test/queries/workarea/search/product_search_test.rb +0 -16
  374. data/test/queries/workarea/search/storefront_search/response_test.rb +26 -0
  375. data/test/queries/workarea/search/storefront_search_test.rb +34 -36
  376. data/test/services/workarea/cancel_order_test.rb +27 -13
  377. data/test/services/workarea/copy_order_test.rb +17 -0
  378. data/test/services/workarea/direct_upload_test.rb +1 -46
  379. data/test/services/workarea/export_report_test.rb +41 -45
  380. data/test/services/workarea/hash_update_test.rb +12 -12
  381. data/test/services/workarea/packaging_test.rb +9 -11
  382. data/test/services/workarea/save_publishing_test.rb +23 -0
  383. data/test/workers/sidekiq/callbacks_test.rb +0 -22
  384. data/test/workers/workarea/deactivate_stale_discounts_test.rb +2 -2
  385. data/test/workers/workarea/index_category_changes_test.rb +5 -7
  386. data/test/workers/workarea/keep_product_index_fresh_test.rb +1 -1
  387. data/test/workers/workarea/process_import_test.rb +0 -6
  388. data/test/workers/workarea/process_search_recommendations_test.rb +4 -5
  389. data/test/workers/workarea/status_reporter_test.rb +2 -1
  390. data/test/workers/workarea/synchronize_user_metrics_test.rb +57 -0
  391. data/test/workers/workarea/update_payment_profile_email_test.rb +27 -0
  392. data/test/workers/workarea/verify_scheduled_releases_test.rb +0 -26
  393. data/workarea-core.gemspec +12 -10
  394. metadata +188 -78
  395. data/app/assets/javascripts/workarea/core/templates/ui_menu_item.jst.ejs +0 -10
  396. data/app/controllers/workarea/admin_guest_browsing.rb +0 -54
  397. data/app/middleware/workarea/rack_cache_config_middleware.rb +0 -19
  398. data/app/queries/workarea/search/search_suggestions.rb +0 -43
  399. data/app/workers/workarea/bust_discount_cache.rb +0 -16
  400. data/app/workers/workarea/clean_user_activity.rb +0 -11
  401. data/app/workers/workarea/undo_release.rb +0 -15
  402. data/app/workers/workarea/update_email.rb +0 -33
  403. data/lib/generators/workarea/docker/USAGE +0 -16
  404. data/lib/generators/workarea/docker/docker_generator.rb +0 -61
  405. data/lib/generators/workarea/docker/templates/.env.erb +0 -6
  406. data/lib/generators/workarea/docker/templates/Dockerfile.erb +0 -48
  407. data/lib/generators/workarea/docker/templates/docker-compose.yml.erb +0 -72
  408. data/lib/generators/workarea/docker/templates/docker-entrypoint.sh.erb +0 -6
  409. data/lib/generators/workarea/docker/templates/docker-sync.yml.erb +0 -8
  410. data/lib/generators/workarea/docker/templates/docker-wait.sh +0 -11
  411. data/lib/generators/workarea/docker/templates/docker.env +0 -16
  412. data/lib/generators/workarea/docker/templates/docker_init.rb.erb +0 -29
  413. data/lib/workarea/configuration/headless_chrome.rb +0 -42
  414. data/lib/workarea/configuration/puma.rb +0 -37
  415. data/lib/workarea/ext/freedom_patches/i18n_js.rb +0 -27
  416. data/lib/workarea/ext/freedom_patches/mongoid_localized_defaults.rb +0 -25
  417. data/lib/workarea/ext/jbuilder/jbuilder_cache.rb +0 -29
  418. data/lib/workarea/ext/referer_parser/parser.decorator +0 -43
  419. data/lib/workarea/queues_pauser.rb +0 -26
  420. data/lib/workarea/robots.rb +0 -9
  421. data/test/generators/workarea/docker_generator_test.rb +0 -156
  422. data/test/javascripts/fixtures/duplicate_id_pass.html.haml +0 -2
  423. data/test/lib/workarea/ext/freedom_patches/mongoid_localized_defaults_test.rb +0 -25
  424. data/test/lib/workarea/ext/referer_parser/parser_test.rb +0 -20
  425. data/test/queries/workarea/search/search_suggestions_test.rb +0 -29
  426. data/test/workers/workarea/undo_release_test.rb +0 -23
  427. data/test/workers/workarea/update_email_test.rb +0 -39
@@ -0,0 +1,18 @@
1
+ module Workarea
2
+ class Order
3
+ class FraudDecision
4
+ include ApplicationDocument
5
+
6
+ embedded_in :order, class_name: 'Workarea::Order'
7
+
8
+ field :decision, type: Symbol, default: :no_decision
9
+ field :analyzer, type: String
10
+ field :message, type: String
11
+ field :response, type: String
12
+
13
+ def declined?
14
+ decision == :declined
15
+ end
16
+ end
17
+ end
18
+ end
@@ -13,6 +13,7 @@ module Workarea
13
13
  field :total_value, type: Money, default: 0
14
14
  field :total_price, type: Money, default: 0
15
15
  field :via, type: String
16
+ field :requires_shipping, type: Boolean, default: true
16
17
 
17
18
  scope :by_newest, -> { desc(:created_at) }
18
19
 
@@ -36,6 +37,10 @@ module Workarea
36
37
  def digital?
37
38
  !!product_attributes['digital']
38
39
  end
40
+ Workarea.deprecation.deprecate_methods(
41
+ Order::Item,
42
+ digital?: 'use `!item.requires_shipping?` to determine if this item is shipped.'
43
+ )
39
44
 
40
45
  # Adds a price adjustment to the item. Does not persist.
41
46
  #
@@ -94,6 +94,7 @@ module Workarea
94
94
  Order.where(
95
95
  placed_at: nil,
96
96
  reminded_at: nil,
97
+ fraud_suspected_at: nil,
97
98
  :checkout_started_at.lte => Workarea.config.order_active_period.ago,
98
99
  :email.exists => true,
99
100
  :email.ne => '',
@@ -8,7 +8,8 @@ module Workarea
8
8
  !order.canceled? &&
9
9
  !order.placed? &&
10
10
  !order.checking_out? &&
11
- !order.abandoned?
11
+ !order.abandoned? &&
12
+ !order.fraud_suspected?
12
13
  end
13
14
  end
14
15
 
@@ -43,6 +44,14 @@ module Workarea
43
44
  order.abandoned?
44
45
  end
45
46
  end
47
+
48
+ class SuspectedFraud
49
+ include StatusCalculator::Status
50
+
51
+ def in_status?
52
+ order.fraud_suspected?
53
+ end
54
+ end
46
55
  end
47
56
  end
48
57
  end
@@ -65,7 +65,7 @@ module Workarea
65
65
  end
66
66
 
67
67
  def tenders
68
- Workarea.config.tender_types.map do |type|
68
+ Workarea.config.tender_types.flat_map do |type|
69
69
  send(type)
70
70
  end.compact
71
71
  end
@@ -80,7 +80,12 @@ module Workarea
80
80
  build_credit_card unless credit_card
81
81
  credit_card.saved_card_id = nil
82
82
  credit_card.attributes = attrs.slice(
83
- *Workarea.config.credit_card_attributes
83
+ :month,
84
+ :year,
85
+ :saved_card_id,
86
+ :number,
87
+ :cvv,
88
+ :amount
84
89
  )
85
90
  save
86
91
  end
@@ -17,6 +17,7 @@ module Workarea
17
17
  validate :valid_number
18
18
  validate :cvv_presence
19
19
  validate :not_expired
20
+ validate :issuer_accepted
20
21
 
21
22
  validates :first_name, presence: true
22
23
  validates :last_name, presence: true
@@ -85,6 +86,17 @@ module Workarea
85
86
  end
86
87
  end
87
88
 
89
+ def issuer_accepted
90
+ unless Workarea.config.credit_card_issuers.value?(issuer)
91
+ message = I18n.t(
92
+ 'workarea.errors.messages.invalid_credit_card_issuer',
93
+ value: issuer,
94
+ issuers: Workarea.config.credit_card_issuers.values.to_sentence
95
+ )
96
+ errors.add(:base, message)
97
+ end
98
+ end
99
+
88
100
  def number_presence
89
101
  if !tokenized? && number.blank?
90
102
  errors.add(:number, I18n.t('errors.messages.blank'))
@@ -1,13 +1,14 @@
1
1
  module Workarea
2
2
  module Pricing
3
3
  class CacheKey
4
- attr_reader :shippings
4
+ attr_reader :shippings, :payment
5
5
  attr_accessor :order
6
6
  delegate :pricing, :discounts, to: :@request
7
7
 
8
- def initialize(order, shippings, request)
8
+ def initialize(order, shippings, payment, request)
9
9
  @order = order
10
10
  @shippings = shippings
11
+ @payment = payment
11
12
  @request = request
12
13
  end
13
14
 
@@ -17,8 +18,9 @@ module Workarea
17
18
  discount_key,
18
19
  order_key,
19
20
  shipping_service_key,
21
+ payment_key,
20
22
  tax_key
21
- ]
23
+ ].compact
22
24
  end
23
25
 
24
26
  def to_s
@@ -43,6 +45,10 @@ module Workarea
43
45
  shippings.map(&:cache_key).join
44
46
  end
45
47
 
48
+ def payment_key
49
+ payment&.cache_key
50
+ end
51
+
46
52
  def tax_key
47
53
  Workarea::Tax::Category.all.map(&:cache_key).join
48
54
  end
@@ -11,11 +11,15 @@ module Workarea
11
11
  def shippings
12
12
  @persisted_shippings
13
13
  end
14
+
15
+ def payment
16
+ @persisted_payment
17
+ end
14
18
  end
15
19
 
16
20
  included do
17
21
  attr_reader :request
18
- delegate :order, :shippings, :pricing, :discounts, to: :request
22
+ delegate :order, :shippings, :payment, :pricing, :discounts, to: :request
19
23
  end
20
24
 
21
25
  module ClassMethods
@@ -5,6 +5,11 @@ module Workarea
5
5
  include Calculator
6
6
 
7
7
  def adjust
8
+ adjust_shipped_items_tax
9
+ adjust_not_shipped_items_tax
10
+ end
11
+
12
+ def adjust_shipped_items_tax
8
13
  shippings.each do |tmp_shipping|
9
14
  next unless tmp_shipping.address.present?
10
15
 
@@ -13,15 +18,37 @@ module Workarea
13
18
  end
14
19
  end
15
20
 
16
- # If doing split shipping (different items go to different shipping
17
- # addresses), decorate this method to return the proper price
18
- # adjustments that match the shipping. (This will have to be added to
19
- # the UI and saved, probably on the Shipping object)
21
+ def adjust_not_shipped_items_tax
22
+ return unless payment&.address.present?
23
+
24
+ ItemTaxApplier.new(
25
+ payment.address,
26
+ not_shipped_items_price_adjustments
27
+ ).apply
28
+ end
29
+
30
+ def shipped_items_price_adjustments
31
+ PriceAdjustmentSet.new(
32
+ order.items.select(&:requires_shipping?).flat_map(&:price_adjustments)
33
+ )
34
+ end
35
+
36
+ def not_shipped_items_price_adjustments
37
+ PriceAdjustmentSet.new(
38
+ order.items.reject(&:requires_shipping?).flat_map(&:price_adjustments)
39
+ )
40
+ end
41
+
42
+ # @deprecated As of v3.5, this class supports applying tax directly to
43
+ # items when they do not require shipping. As a result tax calculation
44
+ # is split on this distinction and this method is no longer sufficient.
45
+ # Instead modify the appropriate method to change the set of price
46
+ # adjustments to consider for tax calculation.
20
47
  #
21
48
  # @return [PriceAdjustmentSet]
22
49
  #
23
50
  def price_adjustments_for(shipping)
24
- order.price_adjustments
51
+ shipped_items_price_adjustments
25
52
  end
26
53
  end
27
54
  end
@@ -91,8 +91,7 @@ module Workarea
91
91
  has_many :redemptions,
92
92
  class_name: 'Workarea::Pricing::Discount::Redemption'
93
93
 
94
- index(active: 1)
95
- index(updated_at: 1)
94
+ index(created_at: 1) # for DeactivateStaleDiscounts
96
95
 
97
96
  validates :name, presence: true
98
97
 
@@ -243,7 +242,7 @@ module Workarea
243
242
  # @return [Time]
244
243
  #
245
244
  def auto_deactivates_at
246
- start = last_redemption.try(:created_at) || updated_at
245
+ start = last_redemption.try(:created_at) || created_at
247
246
  start + Workarea.config.discount_staleness_ttl
248
247
  end
249
248
 
@@ -6,7 +6,8 @@ module Workarea
6
6
 
7
7
  class << self
8
8
  def calculate(discounts, order, shippings)
9
- groups = Rails.cache.fetch('discount_application_groups', expires_in: Workarea.config.cache_expirations.discount_application_groups, race_condition_ttl: 10) do
9
+ expiration = Workarea.config.cache_expirations.discount_application_groups
10
+ groups = Rails.cache.fetch(current_cache_key, expires_in: expiration, race_condition_ttl: 10) do
10
11
  # Ensure an undirected graph of compatibility on discounts
11
12
  discounts.each do |discount|
12
13
  discount.compatible_discount_ids.each do |id|
@@ -30,8 +31,12 @@ module Workarea
30
31
  groups.map { |set| new(set.to_a, order, shippings) }
31
32
  end
32
33
 
33
- def expire_cache
34
- Rails.cache.delete('discount_application_groups')
34
+ def current_cache_key
35
+ [
36
+ 'discount_application_groups',
37
+ Release.current&.id,
38
+ *Segment.current.map(&:id).sort
39
+ ].compact.join('/')
35
40
  end
36
41
 
37
42
  private
@@ -125,8 +125,9 @@ module Workarea
125
125
 
126
126
  def free_product_attributes(sku)
127
127
  ttl = Workarea.config.cache_expirations.free_gift_attributes
128
+ key = ['workarea/free_gift', sku, Release.current&.id].compact.join('/')
128
129
 
129
- Rails.cache.fetch("workarea/free_gift/#{sku}", expires_in: ttl) do
130
+ Rails.cache.fetch(key, expires_in: ttl) do
130
131
  Workarea::OrderItemDetails.find(sku).try(:to_h) || {}
131
132
  end
132
133
  end
@@ -18,8 +18,8 @@ module Workarea
18
18
  belongs_to :discount,
19
19
  class_name: 'Workarea::Pricing::Discount'
20
20
 
21
+ scope :recent, -> { desc(:created_at) }
21
22
  index({ discount_id: 1, email: 1 })
22
- index({ discount_id: 1, created_at: -1 }, { background: true })
23
23
 
24
24
  before_validation :downcase_email
25
25
 
@@ -0,0 +1,41 @@
1
+ module Workarea
2
+ module Pricing
3
+ class ItemTaxApplier
4
+ include TaxApplication
5
+
6
+ def initialize(address, adjustments_to_tax)
7
+ @address = address
8
+ @adjustments_to_tax = adjustments_to_tax
9
+ @adjustments_by_parent = adjustments_to_tax.grouped_by_parent
10
+ end
11
+
12
+ def apply
13
+ @adjustments_to_tax.each { |adjustment| assign_item_tax(adjustment) }
14
+ end
15
+
16
+ private
17
+
18
+ def assign_item_tax(adjustment)
19
+ order_item = adjustment._parent
20
+ taxable_amount = @adjustments_by_parent[order_item].taxable_share_for(adjustment)
21
+ return if taxable_amount.zero?
22
+
23
+ rate = Tax.find_rate(adjustment.data['tax_code'], taxable_amount, @address)
24
+ tax_amounts = calculate_tax_amounts(taxable_amount, rate)
25
+ return if tax_amounts.values.sum.zero?
26
+
27
+ order_item.adjust_pricing(
28
+ price: 'tax',
29
+ calculator: self.class.name,
30
+ description: 'Item Tax',
31
+ amount: tax_amounts.values.sum,
32
+ data: tax_amounts.merge(
33
+ 'adjustment' => adjustment.id,
34
+ 'order_item_id' => adjustment._parent.id,
35
+ 'tax_code' => adjustment.data['tax_code']
36
+ )
37
+ )
38
+ end
39
+ end
40
+ end
41
+ end
@@ -3,6 +3,7 @@ module Workarea
3
3
  class Price
4
4
  include ApplicationDocument
5
5
  include Releasable
6
+ include UnsupportedSegmentation
6
7
 
7
8
  field :min_quantity, type: Integer, default: 1
8
9
  field :regular, type: Money, default: 0
@@ -4,6 +4,7 @@ module Workarea
4
4
  def initialize(order, shippings)
5
5
  @persisted_order = order
6
6
  @persisted_shippings = Array(shippings)
7
+ @persisted_payment = Workarea::Payment.find(order.id) rescue nil
7
8
  end
8
9
 
9
10
  # Builds a duplicate, non-persisted version of the {Workarea::Order}
@@ -44,6 +45,15 @@ module Workarea
44
45
  end
45
46
  end
46
47
 
48
+ def payment
49
+ return unless @persisted_payment.present?
50
+
51
+ @payment ||=
52
+ Workarea::Payment.instantiate(@persisted_payment.as_document).tap do |payment|
53
+ payment.new_record = true # Ensure this isn't persisted by raising duplicate key if saved
54
+ end
55
+ end
56
+
47
57
  # An enumerable of discounts, which allows single a single db query for discounts
48
58
  # to fix N+1 discount queries.
49
59
  #
@@ -99,6 +109,7 @@ module Workarea
99
109
  @cache_key ||= CacheKey.new(
100
110
  @persisted_order,
101
111
  @persisted_shippings,
112
+ @persisted_payment,
102
113
  self
103
114
  )
104
115
  end
@@ -5,6 +5,7 @@ module Workarea
5
5
 
6
6
  include ApplicationDocument
7
7
  include Releasable
8
+ include UnsupportedSegmentation
8
9
 
9
10
  field :_id, type: String
10
11
  field :on_sale, type: Boolean, default: false
@@ -0,0 +1,21 @@
1
+ module Workarea
2
+ module Pricing
3
+ module TaxApplication
4
+ extend ActiveSupport::Concern
5
+ include GuardNegativePrice
6
+
7
+ def calculate_tax_amounts(taxable_amount, rate)
8
+ {
9
+ 'country_amount' => calculate_tax_amount(taxable_amount, rate.country_percentage),
10
+ 'region_amount' => calculate_tax_amount(taxable_amount, rate.region_percentage),
11
+ 'postal_code_amount' => calculate_tax_amount(taxable_amount, rate.postal_code_percentage)
12
+ }
13
+ end
14
+
15
+ def calculate_tax_amount(amount, percentage)
16
+ return 0.to_m unless percentage.present?
17
+ guard_negative_price { amount * percentage }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,7 +1,7 @@
1
1
  module Workarea
2
2
  module Pricing
3
3
  class TaxApplier
4
- include GuardNegativePrice
4
+ include TaxApplication
5
5
 
6
6
  def initialize(shipping, adjustments_to_tax)
7
7
  @shipping = shipping
@@ -30,22 +30,19 @@ module Workarea
30
30
  @shipping.address
31
31
  )
32
32
 
33
- tax_amount = guard_negative_price do
34
- taxable_amount * rate.percentage
35
- end
36
-
37
- return if tax_amount.zero?
33
+ tax_amounts = calculate_tax_amounts(taxable_amount, rate)
34
+ return if tax_amounts.values.sum.zero?
38
35
 
39
36
  @shipping.adjust_pricing(
40
37
  price: 'tax',
41
38
  calculator: self.class.name,
42
39
  description: 'Item Tax',
43
- amount: tax_amount,
44
- data: {
40
+ amount: tax_amounts.values.sum,
41
+ data: tax_amounts.merge(
45
42
  'adjustment' => adjustment.id,
46
43
  'order_item_id' => adjustment._parent.id,
47
44
  'tax_code' => adjustment.data['tax_code']
48
- }
45
+ )
49
46
  )
50
47
  end
51
48
 
@@ -60,7 +57,7 @@ module Workarea
60
57
  end
61
58
 
62
59
  def assign_shipping_tax
63
- return unless shipping_total > 0
60
+ return unless shipping_total.positive?
64
61
 
65
62
  tax_rate = Tax.find_rate(
66
63
  @shipping.shipping_service.tax_code,
@@ -70,18 +67,18 @@ module Workarea
70
67
 
71
68
  return unless tax_rate.charge_on_shipping?
72
69
 
73
- amount = shipping_total * tax_rate.percentage
70
+ amounts = calculate_tax_amounts(shipping_total, tax_rate)
74
71
 
75
- if amount > 0
72
+ if amounts.values.sum.positive?
76
73
  @shipping.adjust_pricing(
77
74
  price: 'tax',
78
75
  calculator: self.class.name,
79
76
  description: 'Shipping Tax',
80
- amount: amount,
81
- data: {
77
+ amount: amounts.values.sum,
78
+ data: amounts.merge(
82
79
  'shipping_service_tax' => true,
83
80
  'tax_code' => tax_rate.category.code
84
- }
81
+ )
85
82
  )
86
83
  end
87
84
  end