workarea-core 3.4.45 → 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/collect_payment.rb +10 -1
  26. data/app/models/workarea/checkout/fraud/analyzer.rb +44 -0
  27. data/app/models/workarea/checkout/fraud/no_decision_analyzer.rb +14 -0
  28. data/app/models/workarea/checkout/fraud/test_analyzer.rb +26 -0
  29. data/app/models/workarea/checkout.rb +18 -6
  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/asset.rb +5 -18
  33. data/app/models/workarea/content/block.rb +8 -2
  34. data/app/models/workarea/content/block_draft.rb +7 -2
  35. data/app/models/workarea/content/block_type.rb +2 -2
  36. data/app/models/workarea/content/block_type_definition.rb +4 -0
  37. data/app/models/workarea/content/preset.rb +1 -1
  38. data/app/models/workarea/content.rb +12 -82
  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/fraud_decision.rb +18 -0
  72. data/app/models/workarea/order/item.rb +5 -0
  73. data/app/models/workarea/order/queries.rb +1 -0
  74. data/app/models/workarea/order/status.rb +10 -1
  75. data/app/models/workarea/order.rb +47 -4
  76. data/app/models/workarea/payment/credit_card.rb +12 -0
  77. data/app/models/workarea/payment.rb +7 -2
  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/application_group.rb +8 -3
  82. data/app/models/workarea/pricing/discount/free_gift.rb +2 -1
  83. data/app/models/workarea/pricing/discount/redemption.rb +1 -1
  84. data/app/models/workarea/pricing/discount.rb +2 -3
  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/activation.rb +45 -0
  95. data/app/models/workarea/release/changes.rb +45 -0
  96. data/app/models/workarea/release/changeset.rb +42 -52
  97. data/app/models/workarea/release/preview.rb +28 -0
  98. data/app/models/workarea/release/status.rb +2 -24
  99. data/app/models/workarea/release.rb +72 -99
  100. data/app/models/workarea/release_session.rb +11 -11
  101. data/app/models/workarea/search/admin/catalog_product.rb +1 -2
  102. data/app/models/workarea/search/admin/fulfillment_sku.rb +27 -0
  103. data/app/models/workarea/search/admin/order.rb +1 -1
  104. data/app/models/workarea/search/admin/pricing_discount.rb +1 -1
  105. data/app/models/workarea/search/admin/release.rb +1 -4
  106. data/app/models/workarea/search/admin/segment.rb +19 -0
  107. data/app/models/workarea/search/admin.rb +17 -39
  108. data/app/models/workarea/search/order_text.rb +23 -6
  109. data/app/models/workarea/search/storefront/category_query.rb +152 -0
  110. data/app/models/workarea/search/storefront/product/categories.rb +11 -45
  111. data/app/models/workarea/search/storefront.rb +33 -29
  112. data/app/models/workarea/segment/first_time_customer.rb +8 -0
  113. data/app/models/workarea/segment/first_time_visitor.rb +12 -0
  114. data/app/models/workarea/segment/life_cycle.rb +44 -0
  115. data/app/models/workarea/segment/loyal_customer.rb +12 -0
  116. data/app/models/workarea/segment/returning_customer.rb +14 -0
  117. data/app/models/workarea/segment/returning_visitor.rb +12 -0
  118. data/app/models/workarea/segment/rules/base.rb +16 -0
  119. data/app/models/workarea/segment/rules/browser_info.rb +29 -0
  120. data/app/models/workarea/segment/rules/geolocation.rb +29 -0
  121. data/app/models/workarea/segment/rules/geolocation_option.rb +53 -0
  122. data/app/models/workarea/segment/rules/last_order.rb +14 -0
  123. data/app/models/workarea/segment/rules/logged_in.rb +13 -0
  124. data/app/models/workarea/segment/rules/orders.rb +17 -0
  125. data/app/models/workarea/segment/rules/revenue.rb +17 -0
  126. data/app/models/workarea/segment/rules/sessions.rb +17 -0
  127. data/app/models/workarea/segment/rules/tags.rb +14 -0
  128. data/app/models/workarea/segment/rules/traffic_referrer.rb +18 -0
  129. data/app/models/workarea/segment.rb +54 -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/exact_matches.rb +1 -1
  170. data/app/queries/workarea/search/storefront_search/response.rb +6 -4
  171. data/app/queries/workarea/search/storefront_search.rb +5 -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/cache.rb +6 -35
  236. data/lib/workarea/changelog.rake +2 -2
  237. data/lib/workarea/configuration/administrable/definition.rb +42 -0
  238. data/lib/workarea/configuration/administrable/field.rb +79 -0
  239. data/lib/workarea/configuration/administrable/fieldset.rb +44 -0
  240. data/lib/workarea/configuration/administrable_options.rb +24 -0
  241. data/lib/workarea/configuration/cache_store.rb +3 -1
  242. data/lib/workarea/configuration/content_blocks.rb +17 -0
  243. data/lib/workarea/configuration/mongoid.rb +1 -4
  244. data/lib/workarea/configuration/session.rb +36 -0
  245. data/lib/workarea/configuration/sidekiq.rb +3 -1
  246. data/lib/workarea/configuration.rb +121 -148
  247. data/lib/workarea/core/engine.rb +3 -58
  248. data/lib/workarea/core.rb +15 -11
  249. data/lib/workarea/elasticsearch/document.rb +8 -15
  250. data/lib/workarea/ext/freedom_patches/action_view_cache_helper.rb +4 -6
  251. data/lib/workarea/ext/freedom_patches/active_support_duration.rb +14 -0
  252. data/lib/workarea/ext/freedom_patches/money.rb +11 -0
  253. data/lib/workarea/ext/freedom_patches/premailer.rb +6 -0
  254. data/lib/workarea/ext/freedom_patches/string.rb +19 -4
  255. data/lib/workarea/ext/mongoid/find_ordered.rb +2 -2
  256. data/lib/workarea/ext/mongoid/lookup_hash.rb +30 -0
  257. data/lib/workarea/geolocation.rb +24 -6
  258. data/lib/workarea/routes_constraints/super_admin.rb +1 -1
  259. data/lib/workarea/version.rb +3 -4
  260. data/lib/workarea/visit.rb +92 -0
  261. data/lib/workarea/warnings.rb +95 -0
  262. data/lib/workarea.rb +102 -3
  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 +13 -11
  394. metadata +196 -92
  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
@@ -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
 
@@ -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
 
@@ -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
@@ -0,0 +1,22 @@
1
+ module Workarea
2
+ module Pricing
3
+ module UnsupportedSegmentation
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ validate :unsupported_segmentation
8
+ end
9
+
10
+ private
11
+
12
+ def unsupported_segmentation
13
+ if active_segment_ids.present?
14
+ errors.add(
15
+ :active_segment_ids,
16
+ I18n.t('workarea.errors.messages.unsupported_segmentation')
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,6 +1,7 @@
1
1
  module Workarea
2
2
  class ProductRule
3
3
  include ApplicationDocument
4
+ include Releasable
4
5
 
5
6
  OPERATORS = %w(
6
7
  greater_than
@@ -22,6 +23,10 @@ module Workarea
22
23
  validates :name, presence: true
23
24
  validates :operator, presence: true
24
25
 
26
+ def self.usable
27
+ scoped.select(&:active?).select(&:valid?)
28
+ end
29
+
25
30
  # The identifier for which admin partials to render for this rule.
26
31
  #
27
32
  # @return [Symbol]
@@ -2,9 +2,12 @@ module Workarea
2
2
  module Releasable
3
3
  extend ActiveSupport::Concern
4
4
  include Mongoid::DocumentPath
5
+ include Release::Activation
6
+ include Segmentable
5
7
 
6
8
  included do
7
9
  field :active, type: Boolean, default: true, localize: Workarea.config.localized_active_fields
10
+ attr_accessor :release_id
8
11
 
9
12
  has_many :changesets,
10
13
  class_name: 'Workarea::Release::Changeset',
@@ -12,11 +15,8 @@ module Workarea
12
15
 
13
16
  validate :slug_unchanged, on: :update
14
17
 
15
- scope :active, -> { where(active: true) }
16
- scope :inactive, -> { where(active: false) }
17
-
18
- around_create :save_activate_with
19
- before_update :save_release_changes
18
+ define_model_callbacks :save_release_changes
19
+ before_update :handle_release_changes
20
20
  after_find :load_release_changes
21
21
  after_destroy :destroy_embedded_changesets
22
22
 
@@ -25,8 +25,22 @@ module Workarea
25
25
  else
26
26
  index(active: 1)
27
27
  end
28
+ end
29
+
30
+ def changesets_with_children
31
+ criteria = Release::Changeset.any_of(
32
+ { releasable_type: self.class.name, releasable_id: id }
33
+ )
28
34
 
29
- attr_accessor :activate_with
35
+ embedded_relations.each do |name, metadata|
36
+ Array.wrap(send(name)).each do |child|
37
+ if child.respond_to?(:changesets_with_children)
38
+ criteria.merge!(child.changesets_with_children)
39
+ end
40
+ end
41
+ end
42
+
43
+ criteria
30
44
  end
31
45
 
32
46
  # A hash of changes for being set on the changeset. It's just a filtered
@@ -35,17 +49,44 @@ module Workarea
35
49
  # @return [Hash]
36
50
  #
37
51
  def release_changes
38
- changes.keys.inject({}) do |memo, key|
39
- old_value, new_value = *changes[key]
52
+ ::Workarea::Release::Changes.new(self).to_h
53
+ end
40
54
 
41
- if Release::Changeset.track_change?(key, old_value, new_value)
42
- memo[key] = new_value
43
- end
55
+ def release_originals
56
+ ::Workarea::Release::Changes.new(self).to_originals_h
57
+ end
44
58
 
45
- memo
59
+ # Get a new instance of this model loaded with changes for the release
60
+ # passed in.
61
+ #
62
+ # @return [Releasable]
63
+ #
64
+ def in_release(release)
65
+ if release.blank? && !changed? # No extra work necessary, return a copy
66
+ result = dup
67
+ result.id = id
68
+ result.release_id = nil
69
+ result
70
+ elsif release.present? && !changed? # We don't have to reload from DB, just apply release changes to a copy
71
+ result = dup
72
+ result.id = id
73
+ result.release_id = release.id
74
+ release.preview.changesets_for(self).each { |cs| cs.apply_to(result) }
75
+ result
76
+ else
77
+ Release.with_current(release) { self.class.find(id) }
46
78
  end
47
79
  end
48
80
 
81
+ # Get a new instance of this model without any release changes. This a new
82
+ # instance without any release changes applied.
83
+ #
84
+ # @return [Releasable]
85
+ #
86
+ def without_release
87
+ in_release(nil)
88
+ end
89
+
49
90
  # Skip the release changeset for the duration of the block. Used when
50
91
  # publishing a changeset, i.e. don't apply/save the release changes since
51
92
  # we actually want to publish.
@@ -54,19 +95,10 @@ module Workarea
54
95
  #
55
96
  def skip_changeset
56
97
  @_skip_changeset = true
57
- result = yield
58
- @_skip_changeset = false
59
- result
60
- end
98
+ yield
61
99
 
62
- # Whether this model becomes active with the current release. Used for some
63
- # funny business when displaying content blocks in the admin. :(
64
- #
65
- # @return [Boolean]
66
- #
67
- def activates_with_current_release?
68
- return false if Release.current.blank?
69
- active? && active_changed? && !was_active?
100
+ ensure
101
+ @_skip_changeset = false
70
102
  end
71
103
 
72
104
  # Persist a to be recalled for publishing later. This is where changesets
@@ -76,34 +108,22 @@ module Workarea
76
108
  #
77
109
  # @param release_id [String]
78
110
  #
79
- def save_changeset(release_id)
80
- return unless release_id.present?
81
-
82
- changeset = Release::Changeset.find_or_initialize_by(
83
- releasable_id: id,
84
- releasable_type: self.class.name,
85
- release_id: release_id
86
- )
87
-
88
- if changeset.persisted? && release_changes.present?
89
- # This is to avoid triggering callbacks - calling #save on a
90
- # persisted Changeset is causing Mongoid to run callbacks on the
91
- # parent document, which resets the changeset changes to previous
92
- # values, not allowing updates to a changeset. #set merges a hash
93
- # field's new value into the old, so a call to #unset is necessary
94
- # to ensure any removed changes are properly deleted.
95
- #
96
- # TODO check in with this before v3 to see if Mongoid has fixed or
97
- # open a Mongoid PR
98
- #
99
- changeset.unset(:changeset)
100
- changeset.set(changeset: release_changes)
101
- elsif release_changes.present?
102
- changeset.document_path = document_path
103
- changeset.changeset = release_changes
104
- changeset.save!
105
- elsif changeset.persisted?
106
- changeset.destroy
111
+ def save_changeset(release)
112
+ return unless release.present?
113
+
114
+ changeset = release.changesets.find_or_initialize_by(releasable: self)
115
+
116
+ run_callbacks :save_release_changes do
117
+ if changeset.persisted? && release_changes.present?
118
+ changeset.update!(changeset: release_changes, original: release_originals)
119
+ elsif release_changes.present?
120
+ changeset.document_path = document_path
121
+ changeset.changeset = release_changes
122
+ changeset.original = release_originals
123
+ changeset.save!
124
+ elsif changeset.persisted?
125
+ changeset.destroy
126
+ end
107
127
  end
108
128
 
109
129
  changes.each do |field, change|
@@ -111,22 +131,25 @@ module Workarea
111
131
  end
112
132
  end
113
133
 
114
- def releasable?
115
- true
134
+ def destroy(*)
135
+ if embedded? && Release.current.present?
136
+ update!(active: false)
137
+ else
138
+ super
139
+ end
116
140
  end
117
141
 
118
142
  private
119
143
 
120
144
  def load_release_changes
121
- # Documents found with .only cause issues
122
- return if readonly? || Release.current.blank?
145
+ return if readonly? || Release.current.blank? # Documents found with .only cause issues
123
146
 
124
- changeset = changesets.find_by(release_id: Release.current.id) rescue nil
125
- changeset.apply_to(self) if changeset.present?
147
+ Release.current.preview.changesets_for(self).each { |c| c.apply_to(self) }
148
+ self.release_id = Release.current.id
126
149
  end
127
150
 
128
- def save_release_changes
129
- save_changeset(Release.current.try(:id)) unless @_skip_changeset
151
+ def handle_release_changes
152
+ save_changeset(Release.current) unless @_skip_changeset
130
153
  end
131
154
 
132
155
  def destroy_embedded_changesets
@@ -138,34 +161,5 @@ module Workarea
138
161
  errors.add(:slug, 'cannot be changed for releases')
139
162
  end
140
163
  end
141
-
142
- def save_activate_with
143
- self.active = false if activate_with?
144
- yield
145
- create_activation_changeset(activate_with) if activate_with?
146
- end
147
-
148
- def activate_with?
149
- activate_with.present? && BSON::ObjectId.legal?(activate_with)
150
- end
151
-
152
- def create_activation_changeset(release_id)
153
- set = changesets.find_or_initialize_by(release_id: release_id)
154
- set.document_path = document_path
155
-
156
- active_changeset = if Workarea.config.localized_active_fields
157
- { 'active' => { I18n.locale => true } }
158
- else
159
- { 'active' => true }
160
- end
161
-
162
- set.changeset = active_changeset
163
- set.save!
164
- end
165
-
166
- def was_active?
167
- (Workarea.config.localized_active_fields && active_was[I18n.locale]) ||
168
- (!Workarea.config.localized_active_fields && active_was)
169
- end
170
164
  end
171
165
  end
@@ -0,0 +1,45 @@
1
+ module Workarea
2
+ class Release
3
+ module Activation
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ around_create :save_activate_with
8
+ attr_accessor :activate_with
9
+ end
10
+
11
+ def save_activate_with
12
+ self.active = false if activate_with?
13
+ yield
14
+ create_activation_changeset(activate_with) if activate_with?
15
+ end
16
+
17
+ def activate_with?
18
+ activate_with.present? && BSON::ObjectId.legal?(activate_with)
19
+ end
20
+
21
+ def create_activation_changeset(release_id)
22
+ set = changesets.find_or_initialize_by(release_id: release_id)
23
+ set.document_path = document_path
24
+
25
+ set.changeset = if Workarea.config.localized_active_fields
26
+ { 'active' => { I18n.locale.to_s => true } }
27
+ else
28
+ { 'active' => true }
29
+ end
30
+ set.original = if Workarea.config.localized_active_fields
31
+ { 'active' => { I18n.locale.to_s => false } }
32
+ else
33
+ { 'active' => false }
34
+ end
35
+
36
+ set.save!
37
+ end
38
+
39
+ def was_active?
40
+ (Workarea.config.localized_active_fields && active_was[I18n.locale.to_s]) ||
41
+ (!Workarea.config.localized_active_fields && active_was)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,45 @@
1
+ module Workarea
2
+ class Release
3
+ class Changes
4
+ attr_reader :releasable
5
+
6
+ def self.tracked_change?(key, old_value, new_value)
7
+ !key.in?(Workarea.config.untracked_release_changes_fields) &&
8
+ (old_value.present? || new_value.present?)
9
+ end
10
+
11
+ def initialize(releasable)
12
+ @releasable = releasable
13
+ end
14
+
15
+ def to_h
16
+ releasable.changes.keys.inject({}) do |memo, key|
17
+ old_value, new_value = *releasable.changes[key]
18
+
19
+ memo[key] = new_value if track_change?(key, old_value, new_value)
20
+ memo
21
+ end
22
+ end
23
+
24
+ def to_originals_h
25
+ releasable.changes.keys.inject({}) do |memo, key|
26
+ old_value, new_value = *releasable.changes[key]
27
+
28
+ memo[key] = old_value if track_change?(key, old_value, new_value)
29
+ memo
30
+ end
31
+ end
32
+
33
+ def track_change?(key, old_value, new_value)
34
+ self.class.tracked_change?(key, old_value, new_value) &&
35
+ !change_appears_in_earlier_release?(key, new_value)
36
+ end
37
+
38
+ def change_appears_in_earlier_release?(key, new_value)
39
+ Release.current.scheduled_before.flat_map(&:changesets).any? do |changeset|
40
+ changeset.releasable == releasable && changeset.includes_change?(key, new_value)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end