solidus_core 4.1.6 → 4.5.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 (308) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/logo/solidus.svg +18 -1
  3. data/app/assets/images/logo/solidus_logo.png +0 -0
  4. data/app/helpers/spree/base_helper.rb +2 -2
  5. data/app/helpers/spree/core/controller_helpers/auth.rb +66 -0
  6. data/app/helpers/spree/core/controller_helpers/common.rb +82 -0
  7. data/app/helpers/spree/core/controller_helpers/order.rb +86 -0
  8. data/app/helpers/spree/core/controller_helpers/payment_parameters.rb +165 -0
  9. data/app/helpers/spree/core/controller_helpers/pricing.rb +19 -0
  10. data/app/helpers/spree/core/controller_helpers/search.rb +16 -0
  11. data/app/helpers/spree/core/controller_helpers/store.rb +19 -0
  12. data/app/helpers/spree/core/controller_helpers/strong_parameters.rb +74 -0
  13. data/app/mailers/spree/base_mailer.rb +1 -1
  14. data/app/mailers/spree/carton_mailer.rb +1 -1
  15. data/app/mailers/spree/order_mailer.rb +3 -3
  16. data/app/mailers/spree/reimbursement_mailer.rb +1 -1
  17. data/app/models/concerns/spree/active_storage_adapter/normalization.rb +1 -1
  18. data/app/models/concerns/spree/active_storage_adapter.rb +1 -1
  19. data/app/models/concerns/spree/display_money.rb +1 -1
  20. data/app/models/concerns/spree/metadata.rb +64 -0
  21. data/app/models/concerns/spree/named_type.rb +2 -0
  22. data/app/models/concerns/spree/ordered_property_value_list.rb +2 -2
  23. data/app/models/concerns/spree/user_address_book.rb +8 -9
  24. data/app/models/concerns/spree/user_methods.rb +3 -3
  25. data/app/models/spree/address.rb +10 -8
  26. data/app/models/spree/adjustment.rb +15 -65
  27. data/app/models/spree/adjustment_reason.rb +2 -0
  28. data/app/models/spree/calculator/returns/default_refund_amount.rb +1 -1
  29. data/app/models/spree/carton.rb +2 -2
  30. data/app/models/spree/core/state_machines/inventory_unit.rb +42 -0
  31. data/app/models/spree/core/state_machines/order/class_methods.rb +217 -0
  32. data/app/models/spree/core/state_machines/order.rb +42 -0
  33. data/app/models/spree/core/state_machines/payment.rb +61 -0
  34. data/app/models/spree/core/state_machines/reimbursement.rb +33 -0
  35. data/app/models/spree/core/state_machines/return_authorization.rb +32 -0
  36. data/app/models/spree/core/state_machines/return_item/acceptance_status.rb +51 -0
  37. data/app/models/spree/core/state_machines/return_item/reception_status.rb +42 -0
  38. data/app/models/spree/core/state_machines/shipment.rb +58 -0
  39. data/app/models/spree/credit_card.rb +12 -9
  40. data/app/models/spree/customer_return.rb +2 -0
  41. data/app/models/spree/deprecated_configurable_class.rb +40 -0
  42. data/app/models/spree/fulfilment_changer.rb +4 -4
  43. data/app/models/spree/inventory_unit.rb +2 -2
  44. data/app/models/spree/item_total.rb +28 -0
  45. data/app/models/spree/legacy_user.rb +1 -0
  46. data/app/models/spree/line_item.rb +22 -4
  47. data/app/models/spree/money.rb +120 -0
  48. data/app/models/spree/null_promotion_adjuster.rb +13 -0
  49. data/app/models/spree/null_promotion_advertiser.rb +9 -0
  50. data/app/models/spree/null_promotion_finder.rb +9 -0
  51. data/app/models/spree/null_promotion_handler.rb +44 -0
  52. data/app/models/spree/option_value.rb +1 -0
  53. data/app/models/spree/order.rb +54 -36
  54. data/app/models/spree/order_cancellations.rb +8 -8
  55. data/app/models/spree/order_inventory.rb +6 -4
  56. data/app/models/spree/order_merger.rb +1 -1
  57. data/app/models/spree/order_mutex.rb +2 -2
  58. data/app/models/spree/order_shipping.rb +9 -9
  59. data/app/models/spree/order_taxation.rb +1 -0
  60. data/app/models/spree/order_updater.rb +19 -40
  61. data/app/models/spree/payment/processing.rb +2 -2
  62. data/app/models/spree/payment.rb +3 -2
  63. data/app/models/spree/payment_create.rb +1 -1
  64. data/app/models/spree/payment_method/bogus_credit_card.rb +14 -9
  65. data/app/models/spree/payment_method/simple_bogus_credit_card.rb +12 -6
  66. data/app/models/spree/payment_method/store_credit.rb +1 -1
  67. data/app/models/spree/payment_method.rb +3 -1
  68. data/app/models/spree/payment_source.rb +5 -1
  69. data/app/models/spree/permission_set.rb +11 -0
  70. data/app/models/spree/permission_sets/base.rb +45 -0
  71. data/app/models/spree/permission_sets/configuration_display.rb +53 -0
  72. data/app/models/spree/permission_sets/configuration_management.rb +52 -0
  73. data/app/models/spree/permission_sets/dashboard_display.rb +28 -0
  74. data/app/models/spree/permission_sets/default_customer.rb +83 -0
  75. data/app/models/spree/permission_sets/order_display.rb +50 -0
  76. data/app/models/spree/permission_sets/order_management.rb +50 -0
  77. data/app/models/spree/permission_sets/product_display.rb +43 -0
  78. data/app/models/spree/permission_sets/product_management.rb +47 -0
  79. data/app/models/spree/permission_sets/restricted_stock_display.rb +33 -0
  80. data/app/models/spree/permission_sets/restricted_stock_management.rb +33 -0
  81. data/app/models/spree/permission_sets/stock_display.rb +26 -0
  82. data/app/models/spree/permission_sets/stock_management.rb +26 -0
  83. data/app/models/spree/permission_sets/super_user.rb +26 -0
  84. data/app/models/spree/permission_sets/user_display.rb +27 -0
  85. data/app/models/spree/permission_sets/user_management.rb +44 -0
  86. data/app/models/spree/preference.rb +1 -1
  87. data/app/models/spree/product.rb +13 -9
  88. data/app/models/spree/refund.rb +3 -1
  89. data/app/models/spree/refund_reason.rb +6 -1
  90. data/app/models/spree/reimbursement.rb +4 -4
  91. data/app/models/spree/reimbursement_performer.rb +3 -3
  92. data/app/models/spree/reimbursement_tax_calculator.rb +2 -2
  93. data/app/models/spree/reimbursement_type/credit.rb +1 -1
  94. data/app/models/spree/reimbursement_type/reimbursement_helpers.rb +6 -6
  95. data/app/models/spree/reimbursement_type/store_credit.rb +1 -1
  96. data/app/models/spree/reimbursement_type.rb +6 -1
  97. data/app/models/spree/return_authorization.rb +2 -0
  98. data/app/models/spree/return_item.rb +10 -10
  99. data/app/models/spree/return_reason.rb +6 -1
  100. data/app/models/spree/role.rb +3 -1
  101. data/app/models/spree/role_permission.rb +8 -0
  102. data/app/models/spree/shipment.rb +9 -7
  103. data/app/models/spree/shipping_category.rb +2 -0
  104. data/app/models/spree/shipping_rate.rb +2 -3
  105. data/app/models/spree/{order_contents.rb → simple_order_contents.rb} +8 -12
  106. data/app/models/spree/stock/estimator.rb +1 -1
  107. data/app/models/spree/stock/inventory_unit_builder.rb +1 -1
  108. data/app/models/spree/stock/package.rb +2 -2
  109. data/app/models/spree/stock/simple_coordinator.rb +36 -22
  110. data/app/models/spree/stock_item.rb +1 -0
  111. data/app/models/spree/stock_location.rb +5 -5
  112. data/app/models/spree/store.rb +3 -1
  113. data/app/models/spree/store_credit.rb +17 -15
  114. data/app/models/spree/store_credit_event.rb +4 -3
  115. data/app/models/spree/store_credit_reason.rb +6 -1
  116. data/app/models/spree/store_selector/by_server_name.rb +1 -1
  117. data/app/models/spree/tax/tax_helpers.rb +12 -1
  118. data/app/models/spree/tax_calculator/default.rb +3 -3
  119. data/app/models/spree/tax_calculator/shipping_rate.rb +1 -1
  120. data/app/models/spree/tax_category.rb +3 -1
  121. data/app/models/spree/tax_rate.rb +7 -3
  122. data/app/models/spree/taxon.rb +22 -2
  123. data/app/models/spree/taxon_brand_selector.rb +22 -0
  124. data/app/models/spree/taxonomy.rb +2 -2
  125. data/app/models/spree/unauthorized_redirect_handler.rb +24 -0
  126. data/app/models/spree/unit_cancel.rb +1 -2
  127. data/app/models/spree/user_address.rb +9 -3
  128. data/app/models/spree/variant/scopes.rb +4 -0
  129. data/app/models/spree/variant/vat_price_generator.rb +1 -1
  130. data/app/models/spree/variant.rb +21 -8
  131. data/app/models/spree/wallet.rb +2 -2
  132. data/app/views/spree/order_mailer/cancel_email.html.erb +1 -1
  133. data/app/views/spree/order_mailer/cancel_email.text.erb +1 -1
  134. data/app/views/spree/order_mailer/confirm_email.html.erb +5 -5
  135. data/app/views/spree/order_mailer/confirm_email.text.erb +5 -5
  136. data/app/views/spree/order_mailer/inventory_cancellation_email.html.erb +0 -1
  137. data/config/locales/en.yml +33 -90
  138. data/db/default/spree/permission_sets.rb +10 -0
  139. data/db/default/spree/return_reasons.rb +3 -1
  140. data/db/default/spree/states.rb +1 -1
  141. data/db/migrate/20160101010000_solidus_one_four.rb +0 -127
  142. data/db/migrate/20220419170826_remove_archived_user_addresses.rb +12 -0
  143. data/db/migrate/20230427095534_drop_deprecated_address_id_from_shipments.rb +1 -1
  144. data/db/migrate/20240821173254_create_spree_permission_sets_in_core.rb +9 -0
  145. data/db/migrate/20240821173341_create_spree_roles_permissions_in_core.rb +9 -0
  146. data/db/migrate/20240821173641_add_description_to_spree_roles.rb +5 -0
  147. data/db/migrate/20240904152041_add_privilege_and_category_to_spree_permission_sets.rb +6 -0
  148. data/db/migrate/20250129061658_add_metadata_to_spree_resources.rb +28 -0
  149. data/db/migrate/20250201172950_add_gtin_and_condition_to_spree_variant.rb +6 -0
  150. data/db/migrate/20250207104016_add_primary_taxon_to_products.rb +7 -0
  151. data/db/migrate/20250221152004_add_metadata_to_users.rb +13 -0
  152. data/db/seeds.rb +1 -0
  153. data/lib/generators/solidus/install/app_templates/authentication/custom.rb +0 -5
  154. data/lib/generators/solidus/install/app_templates/frontend/starter.rb +1 -1
  155. data/lib/generators/solidus/install/install_generator.rb +64 -15
  156. data/lib/generators/solidus/install/templates/config/initializers/spree.rb.tt +15 -12
  157. data/lib/generators/solidus/update/update_generator.rb +1 -1
  158. data/lib/generators/spree/dummy/dummy_generator.rb +1 -1
  159. data/lib/generators/spree/dummy/templates/rails/application.rb.tt +1 -1
  160. data/lib/generators/spree/dummy/templates/rails/database.yml +41 -93
  161. data/lib/generators/spree/dummy/templates/rails/manifest.js +3 -0
  162. data/lib/generators/spree/dummy/templates/rails/test.rb +6 -1
  163. data/lib/spree/app_configuration.rb +102 -67
  164. data/lib/spree/core/class_constantizer.rb +2 -2
  165. data/lib/spree/core/controller_helpers/auth.rb +5 -61
  166. data/lib/spree/core/controller_helpers/common.rb +5 -80
  167. data/lib/spree/core/controller_helpers/order.rb +5 -86
  168. data/lib/spree/core/controller_helpers/payment_parameters.rb +5 -163
  169. data/lib/spree/core/controller_helpers/pricing.rb +5 -17
  170. data/lib/spree/core/controller_helpers/search.rb +5 -14
  171. data/lib/spree/core/controller_helpers/store.rb +5 -17
  172. data/lib/spree/core/controller_helpers/strong_parameters.rb +5 -71
  173. data/lib/spree/core/engine.rb +13 -5
  174. data/lib/spree/core/environment/calculators.rb +35 -3
  175. data/lib/spree/core/environment/promotions.rb +25 -4
  176. data/lib/spree/core/environment_extension.rb +16 -2
  177. data/lib/spree/core/importer/order.rb +5 -5
  178. data/lib/spree/core/importer/product.rb +3 -3
  179. data/lib/spree/core/nested_class_set.rb +28 -0
  180. data/lib/spree/core/null_promotion_configuration.rb +84 -0
  181. data/lib/spree/core/product_filters.rb +1 -1
  182. data/lib/spree/core/search/variant.rb +2 -2
  183. data/lib/spree/core/state_machines/inventory_unit.rb +5 -40
  184. data/lib/spree/core/state_machines/order.rb +5 -251
  185. data/lib/spree/core/state_machines/payment.rb +5 -59
  186. data/lib/spree/core/state_machines/reimbursement.rb +5 -31
  187. data/lib/spree/core/state_machines/return_authorization.rb +5 -30
  188. data/lib/spree/core/state_machines/return_item/acceptance_status.rb +5 -49
  189. data/lib/spree/core/state_machines/return_item/reception_status.rb +5 -40
  190. data/lib/spree/core/state_machines/shipment.rb +5 -56
  191. data/lib/spree/core/state_machines.rb +48 -81
  192. data/lib/spree/core/validators/email.rb +1 -1
  193. data/lib/spree/core/version.rb +2 -2
  194. data/lib/spree/core.rb +2 -14
  195. data/lib/spree/deprecator.rb +9 -0
  196. data/lib/spree/i18n.rb +1 -1
  197. data/lib/spree/mailer_previews/carton_preview.rb +1 -1
  198. data/lib/spree/money.rb +5 -118
  199. data/lib/spree/permission_sets/base.rb +5 -30
  200. data/lib/spree/permission_sets/configuration_display.rb +5 -41
  201. data/lib/spree/permission_sets/configuration_management.rb +5 -40
  202. data/lib/spree/permission_sets/dashboard_display.rb +5 -14
  203. data/lib/spree/permission_sets/default_customer.rb +5 -71
  204. data/lib/spree/permission_sets/order_display.rb +5 -38
  205. data/lib/spree/permission_sets/order_management.rb +5 -38
  206. data/lib/spree/permission_sets/product_display.rb +5 -31
  207. data/lib/spree/permission_sets/product_management.rb +5 -35
  208. data/lib/spree/permission_sets/restricted_stock_display.rb +5 -21
  209. data/lib/spree/permission_sets/restricted_stock_management.rb +5 -21
  210. data/lib/spree/permission_sets/stock_display.rb +5 -14
  211. data/lib/spree/permission_sets/stock_management.rb +5 -14
  212. data/lib/spree/permission_sets/super_user.rb +5 -14
  213. data/lib/spree/permission_sets/user_display.rb +5 -15
  214. data/lib/spree/permission_sets/user_management.rb +5 -32
  215. data/lib/spree/permission_sets.rb +5 -18
  216. data/lib/spree/permitted_attributes.rb +21 -9
  217. data/lib/spree/preferences/configuration.rb +4 -0
  218. data/lib/spree/preferences/persistable.rb +7 -1
  219. data/lib/spree/preferences/store.rb +2 -2
  220. data/lib/spree/testing_support/capybara_ext.rb +11 -1
  221. data/lib/spree/testing_support/common_rake.rb +1 -0
  222. data/lib/spree/testing_support/dummy_ability.rb +7 -0
  223. data/lib/spree/testing_support/dummy_app/assets/stylesheets/solidus_admin/tailwind.css +1 -0
  224. data/lib/spree/testing_support/dummy_app/database.yml +37 -46
  225. data/lib/spree/testing_support/dummy_app/migrations.rb +8 -15
  226. data/lib/spree/testing_support/dummy_app/rake_tasks.rb +3 -6
  227. data/lib/spree/testing_support/dummy_app.rb +33 -19
  228. data/lib/spree/testing_support/factories/adjustment_factory.rb +1 -2
  229. data/lib/spree/testing_support/factories/calculator_factory.rb +1 -5
  230. data/lib/spree/testing_support/factories/carton_factory.rb +2 -2
  231. data/lib/spree/testing_support/factories/customer_return_factory.rb +2 -2
  232. data/lib/spree/testing_support/factories/inventory_unit_factory.rb +3 -3
  233. data/lib/spree/testing_support/factories/order_factory.rb +13 -24
  234. data/lib/spree/testing_support/factories/product_factory.rb +1 -1
  235. data/lib/spree/testing_support/factories/shipment_factory.rb +1 -1
  236. data/lib/spree/testing_support/factories/stock_item_factory.rb +5 -1
  237. data/lib/spree/testing_support/factories/stock_package_factory.rb +1 -1
  238. data/lib/spree/testing_support/factories/user_factory.rb +1 -1
  239. data/lib/spree/testing_support/factories/zone_factory.rb +1 -1
  240. data/lib/spree/testing_support/order_walkthrough.rb +3 -3
  241. data/lib/spree/testing_support/shared_examples/calculator.rb +10 -0
  242. data/lib/spree/testing_support/shared_examples/order_factory.rb +141 -0
  243. data/lib/spree/testing_support/shared_examples/working_factory.rb +15 -0
  244. data/lib/tasks/colorado_delivery_fee.rake +2 -2
  245. data/solidus_core.gemspec +7 -10
  246. metadata +107 -109
  247. data/app/jobs/spree/promotion_code_batch_job.rb +0 -26
  248. data/app/mailers/spree/promotion_code_batch_mailer.rb +0 -15
  249. data/app/models/spree/calculator/distributed_amount.rb +0 -33
  250. data/app/models/spree/calculator/flat_percent_item_total.rb +0 -23
  251. data/app/models/spree/calculator/flexi_rate.rb +0 -22
  252. data/app/models/spree/calculator/percent_on_line_item.rb +0 -13
  253. data/app/models/spree/calculator/tiered_flat_rate.rb +0 -52
  254. data/app/models/spree/calculator/tiered_percent.rb +0 -62
  255. data/app/models/spree/line_item_action.rb +0 -8
  256. data/app/models/spree/order_promotion.rb +0 -27
  257. data/app/models/spree/promotion/actions/create_adjustment.rb +0 -81
  258. data/app/models/spree/promotion/actions/create_item_adjustments.rb +0 -98
  259. data/app/models/spree/promotion/actions/create_quantity_adjustments.rb +0 -139
  260. data/app/models/spree/promotion/actions/free_shipping.rb +0 -59
  261. data/app/models/spree/promotion/order_adjustments_recalculator.rb +0 -92
  262. data/app/models/spree/promotion/rules/first_order.rb +0 -38
  263. data/app/models/spree/promotion/rules/first_repeat_purchase_since.rb +0 -36
  264. data/app/models/spree/promotion/rules/item_total.rb +0 -86
  265. data/app/models/spree/promotion/rules/nth_order.rb +0 -45
  266. data/app/models/spree/promotion/rules/one_use_per_user.rb +0 -25
  267. data/app/models/spree/promotion/rules/option_value.rb +0 -50
  268. data/app/models/spree/promotion/rules/product.rb +0 -86
  269. data/app/models/spree/promotion/rules/store.rb +0 -26
  270. data/app/models/spree/promotion/rules/taxon.rb +0 -91
  271. data/app/models/spree/promotion/rules/user.rb +0 -34
  272. data/app/models/spree/promotion/rules/user_logged_in.rb +0 -20
  273. data/app/models/spree/promotion/rules/user_role.rb +0 -45
  274. data/app/models/spree/promotion.rb +0 -271
  275. data/app/models/spree/promotion_action.rb +0 -47
  276. data/app/models/spree/promotion_category.rb +0 -8
  277. data/app/models/spree/promotion_chooser.rb +0 -34
  278. data/app/models/spree/promotion_code/batch_builder.rb +0 -64
  279. data/app/models/spree/promotion_code.rb +0 -54
  280. data/app/models/spree/promotion_code_batch.rb +0 -27
  281. data/app/models/spree/promotion_handler/cart.rb +0 -75
  282. data/app/models/spree/promotion_handler/coupon.rb +0 -123
  283. data/app/models/spree/promotion_handler/page.rb +0 -26
  284. data/app/models/spree/promotion_handler/shipping.rb +0 -61
  285. data/app/models/spree/promotion_rule.rb +0 -55
  286. data/app/models/spree/promotion_rule_role.rb +0 -8
  287. data/app/models/spree/promotion_rule_store.rb +0 -10
  288. data/app/models/spree/promotion_rule_taxon.rb +0 -8
  289. data/app/models/spree/promotion_rule_user.rb +0 -10
  290. data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_errored.text.erb +0 -2
  291. data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_finished.text.erb +0 -2
  292. data/bin/rails +0 -13
  293. data/db/migrate/20161017102621_create_spree_promotion_code_batch.rb +0 -38
  294. data/db/migrate/20180202190713_create_promotion_rule_stores.rb +0 -12
  295. data/db/migrate/20180328172631_add_join_characters_to_promotion_code_batch.rb +0 -11
  296. data/db/migrate/20190106184413_remove_code_from_spree_promotions.rb +0 -42
  297. data/db/migrate/20220317165036_set_promotions_with_any_policy_to_all_if_possible.rb +0 -20
  298. data/db/migrate/20230322085416_remove_match_policy_from_spree_promotion.rb +0 -5
  299. data/db/migrate/20230325132905_remove_unused_columns_from_promotion_rules.rb +0 -6
  300. data/db/migrate/20230325161633_drop_unused_promo_action_line_items.rb +0 -13
  301. data/lib/generators/spree/dummy/templates/rails/script/rails +0 -6
  302. data/lib/solidus/migrations/promotions_with_code_handlers.rb +0 -66
  303. data/lib/spree/permission_sets/promotion_display.rb +0 -25
  304. data/lib/spree/permission_sets/promotion_management.rb +0 -25
  305. data/lib/spree/testing_support/factories/order_promotion_factory.rb +0 -8
  306. data/lib/spree/testing_support/factories/promotion_category_factory.rb +0 -7
  307. data/lib/spree/testing_support/factories/promotion_code_factory.rb +0 -8
  308. data/lib/spree/testing_support/factories/promotion_factory.rb +0 -98
@@ -24,7 +24,7 @@ module Spree
24
24
  money_method = { money_method => {} } unless money_method.is_a? Hash
25
25
  money_method.each do |method_name, opts|
26
26
  define_method("display_#{method_name}") do
27
- default_opts = respond_to?(:currency) ? { currency: currency } : {}
27
+ default_opts = respond_to?(:currency) ? { currency: } : {}
28
28
  Spree::Money.new(send(method_name), default_opts.merge(opts))
29
29
  end
30
30
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Metadata
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ attribute :customer_metadata, :json, default: {}
9
+ attribute :admin_metadata, :json, default: {}
10
+
11
+ validate :validate_metadata_limits, if: :validate_metadata_enabled?
12
+ end
13
+
14
+ class_methods do
15
+ def meta_data_columns
16
+ %i[customer_metadata admin_metadata]
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def validate_metadata_enabled?
23
+ Spree::Config.meta_data_validation_enabled
24
+ end
25
+
26
+ def validate_metadata_limits
27
+ self.class.meta_data_columns.each { |column| validate_metadata_column(column) }
28
+ end
29
+
30
+ def validate_metadata_column(column)
31
+ config = Spree::Config
32
+ metadata = send(column)
33
+
34
+ return if metadata.nil?
35
+
36
+ # Check for maximum number of keys
37
+ validate_metadata_keys_count(metadata, column, config.meta_data_max_keys)
38
+
39
+ # Check for maximum key and value size
40
+ metadata.each do |key, value|
41
+ validate_metadata_key(key, column, config.meta_data_max_key_length)
42
+ validate_metadata_value(key, value, column, config.meta_data_max_value_length)
43
+ end
44
+ end
45
+
46
+ def validate_metadata_keys_count(metadata, column, max_keys)
47
+ return unless metadata.keys.count > max_keys
48
+
49
+ errors.add(column, "must not have more than #{max_keys} keys")
50
+ end
51
+
52
+ def validate_metadata_key(key, column, max_key_length)
53
+ return unless key.to_s.length > max_key_length
54
+
55
+ errors.add(column, "key '#{key}' exceeds #{max_key_length} characters")
56
+ end
57
+
58
+ def validate_metadata_value(key, value, column, max_value_length)
59
+ return unless value.to_s.length > max_value_length
60
+
61
+ errors.add(column, "value for key '#{key}' exceeds #{max_value_length} characters")
62
+ end
63
+ end
64
+ end
@@ -5,6 +5,8 @@ module Spree
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
+ Spree.deprecator.warn "Spree::NamedType is deprecated. Please set scopes and validations locally instead.", caller
9
+
8
10
  scope :active, -> { where(active: true) }
9
11
  default_scope -> { order(arel_table[:name].lower) }
10
12
 
@@ -18,8 +18,8 @@ module Spree
18
18
 
19
19
  def property_name=(name)
20
20
  unless name.blank?
21
- unless property = Spree::Property.find_by(name: name)
22
- property = Spree::Property.create(name: name, presentation: name)
21
+ unless property = Spree::Property.find_by(name:)
22
+ property = Spree::Property.create(name:, presentation: name)
23
23
  end
24
24
  self.property = property
25
25
  end
@@ -5,7 +5,7 @@ module Spree
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- has_many :user_addresses, -> { active }, foreign_key: "user_id", class_name: "Spree::UserAddress" do
8
+ has_many :user_addresses, foreign_key: "user_id", class_name: "Spree::UserAddress" do
9
9
  def find_first_by_address_values(address_attrs)
10
10
  detect { |ua| ua.address == Spree::Address.new(address_attrs) }
11
11
  end
@@ -22,7 +22,7 @@ module Spree
22
22
  end
23
23
 
24
24
  if user_address.persisted?
25
- user_address.update!(column_for_default => true, archived: false)
25
+ user_address.update!(column_for_default => true)
26
26
  else
27
27
  user_address.write_attribute(column_for_default, true)
28
28
  end
@@ -120,7 +120,7 @@ module Spree
120
120
  remove_from_address_book(address_attributes[:id])
121
121
  end
122
122
 
123
- user_addresses.mark_default(user_address, address_type: address_type) if default || first_one
123
+ user_addresses.mark_default(user_address, address_type:) if default || first_one
124
124
 
125
125
  if persisted?
126
126
  user_address.save!
@@ -140,18 +140,18 @@ module Spree
140
140
  end
141
141
 
142
142
  def mark_default_ship_address(address)
143
- user_addresses.mark_default(user_addresses.find_by(address: address))
143
+ user_addresses.mark_default(user_addresses.find_by(address:))
144
144
  end
145
145
 
146
146
  def mark_default_bill_address(address)
147
- user_addresses.mark_default(user_addresses.find_by(address: address), address_type: :billing)
147
+ user_addresses.mark_default(user_addresses.find_by(address:), address_type: :billing)
148
148
  end
149
149
 
150
150
  def remove_from_address_book(address_id)
151
- user_address = user_addresses.find_by(address_id: address_id)
151
+ user_address = user_addresses.find_by(address_id:)
152
152
  if user_address
153
153
  remove_user_address_reference(address_id)
154
- user_address.update(archived: true, default: false)
154
+ user_address.destroy!
155
155
  else
156
156
  false
157
157
  end
@@ -160,10 +160,9 @@ module Spree
160
160
  private
161
161
 
162
162
  def prepare_user_address(new_address)
163
- user_address = user_addresses.all_historical.find_first_by_address_values(new_address.attributes)
163
+ user_address = user_addresses.find_first_by_address_values(new_address.attributes)
164
164
  user_address ||= user_addresses.build
165
165
  user_address.address = new_address
166
- user_address.archived = false
167
166
  user_address
168
167
  end
169
168
 
@@ -58,7 +58,7 @@ module Spree
58
58
  def last_incomplete_spree_order(store: nil, only_frontend_viewable: true)
59
59
  self_orders = orders
60
60
  self_orders = self_orders.where(frontend_viewable: true) if only_frontend_viewable
61
- self_orders = self_orders.where(store: store) if store
61
+ self_orders = self_orders.where(store:) if store
62
62
  self_orders = self_orders.where('updated_at > ?', Spree::Config.completable_order_updated_cutoff_days.days.ago) if Spree::Config.completable_order_updated_cutoff_days
63
63
  self_orders = self_orders.where('created_at > ?', Spree::Config.completable_order_created_cutoff_days.days.ago) if Spree::Config.completable_order_created_cutoff_days
64
64
  last_order = self_orders.order(:created_at).last
@@ -73,8 +73,8 @@ module Spree
73
73
 
74
74
  def display_available_store_credit_total(currency:)
75
75
  Spree::Money.new(
76
- available_store_credit_total(currency: currency),
77
- currency: currency,
76
+ available_store_credit_total(currency:),
77
+ currency:,
78
78
  )
79
79
  end
80
80
 
@@ -28,8 +28,10 @@ module Spree
28
28
 
29
29
  self.allowed_ransackable_attributes = %w[name]
30
30
 
31
- scope :with_values, ->(attributes) do
32
- where(value_attributes(attributes))
31
+ unless ActiveRecord::Relation.method_defined? :with_values # Rails 7.1+
32
+ scope :with_values, ->(attributes) do
33
+ where(value_attributes(attributes))
34
+ end
33
35
  end
34
36
 
35
37
  # @return [Address] an address with default attributes
@@ -95,14 +97,14 @@ module Spree
95
97
  # @return [Hash] an ActiveMerchant compatible address hash
96
98
  def active_merchant_hash
97
99
  {
98
- name: name,
99
- address1: address1,
100
- address2: address2,
101
- city: city,
100
+ name:,
101
+ address1:,
102
+ address2:,
103
+ city:,
102
104
  state: state_text,
103
105
  zip: zipcode,
104
106
  country: country.try(:iso),
105
- phone: phone
107
+ phone:
106
108
  }
107
109
  end
108
110
 
@@ -130,7 +132,7 @@ module Spree
130
132
  # @return [Country] setter that sets self.country to the Country with a matching 2 letter iso
131
133
  # @raise [ActiveRecord::RecordNotFound] if country with the iso doesn't exist
132
134
  def country_iso=(iso)
133
- self.country = Spree::Country.find_by!(iso: iso)
135
+ self.country = Spree::Country.find_by!(iso:)
134
136
  end
135
137
 
136
138
  def country_iso
@@ -4,29 +4,18 @@ module Spree
4
4
  # Adjustments represent a change to the +item_total+ of an Order. Each
5
5
  # adjustment has an +amount+ that can be either positive or negative.
6
6
  #
7
- # Adjustments can be "opened" or "closed". Once an adjustment is closed, it
7
+ # Adjustments can be "unfinalized" or "finalized". Once an adjustment is finalized, it
8
8
  # will not be automatically updated.
9
- #
10
- # == Boolean attributes
11
- #
12
- # 1. *eligible?*
13
- #
14
- # This boolean attributes stores whether this adjustment is currently
15
- # eligible for its order. Only eligible adjustments count towards the
16
- # order's adjustment total. This allows an adjustment to be preserved if
17
- # it becomes ineligible so it might be reinstated.
18
9
  class Adjustment < Spree::Base
19
10
  belongs_to :adjustable, polymorphic: true, touch: true, optional: true
20
11
  belongs_to :source, polymorphic: true, optional: true
21
12
  belongs_to :order, class_name: 'Spree::Order', inverse_of: :all_adjustments, optional: true
22
- belongs_to :promotion_code, class_name: 'Spree::PromotionCode', optional: true
23
13
  belongs_to :adjustment_reason, class_name: 'Spree::AdjustmentReason', inverse_of: :adjustments, optional: true
24
14
 
25
15
  validates :adjustable, presence: true
26
16
  validates :order, presence: true
27
17
  validates :label, presence: true
28
18
  validates :amount, numericality: true
29
- validates :promotion_code, presence: true, if: :require_promotion_code?
30
19
 
31
20
  scope :not_finalized, -> { where(finalized: false) }
32
21
  scope :finalized, -> { where(finalized: true) }
@@ -38,16 +27,23 @@ module Spree
38
27
  end
39
28
  scope :price, -> { where(adjustable_type: 'Spree::LineItem') }
40
29
  scope :shipping, -> { where(adjustable_type: 'Spree::Shipment') }
41
- scope :eligible, -> { where(eligible: true) }
30
+ scope :eligible, -> { all }
31
+ class << self
32
+ deprecate :eligible, deprecator: Spree.deprecator
33
+ end
42
34
  scope :charge, -> { where("#{quoted_table_name}.amount >= 0") }
43
35
  scope :credit, -> { where("#{quoted_table_name}.amount < 0") }
44
36
  scope :nonzero, -> { where("#{quoted_table_name}.amount != 0") }
45
- scope :promotion, -> { where(source_type: 'Spree::PromotionAction') }
46
- scope :non_promotion, -> { where.not(source_type: 'Spree::PromotionAction') }
37
+ scope :promotion, -> { where(source_type: Spree::Config.adjustment_promotion_source_types.map(&:to_s)) }
38
+ scope :non_promotion, -> { where.not(source_type: Spree::Config.adjustment_promotion_source_types.map(&:to_s)) }
47
39
  scope :return_authorization, -> { where(source_type: "Spree::ReturnAuthorization") }
48
40
  scope :is_included, -> { where(included: true) }
49
41
  scope :additional, -> { where(included: false) }
50
42
 
43
+ singleton_class.deprecate :return_authorization, deprecator: Spree.deprecator
44
+
45
+ allowed_ransackable_attributes << 'label'
46
+
51
47
  extend DisplayMoney
52
48
  money_methods :amount
53
49
 
@@ -73,7 +69,7 @@ module Spree
73
69
 
74
70
  # @return [Boolean] true when this is a promotion adjustment (Promotion adjustments have a {PromotionAction} source)
75
71
  def promotion?
76
- source_type == 'Spree::PromotionAction'
72
+ source_type.to_s.in?(Spree::Config.adjustment_promotion_source_types.map(&:to_s))
77
73
  end
78
74
 
79
75
  # @return [Boolean] true when this is a tax adjustment (Tax adjustments have a {TaxRate} source)
@@ -86,55 +82,9 @@ module Spree
86
82
  source_type == 'Spree::UnitCancel'
87
83
  end
88
84
 
89
- # Recalculate and persist the amount from this adjustment's source based on
90
- # the adjustable ({Order}, {Shipment}, or {LineItem})
91
- #
92
- # If the adjustment has no source (such as when created manually from the
93
- # admin) or is closed, this is a noop.
94
- #
95
- # @return [BigDecimal] New amount of this adjustment
96
- def recalculate
97
- if finalized? && !tax?
98
- return amount
99
- end
100
-
101
- # If the adjustment has no source, do not attempt to re-calculate the
102
- # amount.
103
- # Some scenarios where this happens:
104
- # - Adjustments that are manually created via the admin backend
105
- # - PromotionAction adjustments where the PromotionAction was deleted
106
- # after the order was completed.
107
- if source.present?
108
- self.amount = source.compute_amount(adjustable)
109
-
110
- if promotion?
111
- self.eligible = calculate_eligibility
112
- end
113
-
114
- # Persist only if changed
115
- # This is only not a save! to avoid the extra queries to load the order
116
- # (for validations) and to touch the adjustment.
117
- update_columns(eligible: eligible, amount: amount, updated_at: Time.current) if changed?
118
- end
119
- amount
120
- end
121
-
122
- # Calculates based on attached promotion (if this is a promotion
123
- # adjustment) whether this promotion is still eligible.
124
- # @api private
125
- # @return [true,false] Whether this adjustment is eligible
126
- def calculate_eligibility
127
- if !finalized? && source && promotion?
128
- source.promotion.eligible?(adjustable, promotion_code: promotion_code)
129
- else
130
- eligible?
131
- end
132
- end
133
-
134
- private
135
-
136
- def require_promotion_code?
137
- promotion? && !source.promotion.apply_automatically && source.promotion.codes.any?
85
+ def eligible?
86
+ true
138
87
  end
88
+ alias_method :eligible, :eligible?
139
89
  end
140
90
  end
@@ -8,5 +8,7 @@ module Spree
8
8
  validates :code, presence: true, uniqueness: { case_sensitive: false, allow_blank: true }
9
9
 
10
10
  scope :active, -> { where(active: true) }
11
+
12
+ self.allowed_ransackable_attributes = %w[name code]
11
13
  end
12
14
  end
@@ -14,7 +14,7 @@ module Spree
14
14
  private
15
15
 
16
16
  def weighted_order_adjustment_amount(inventory_unit)
17
- inventory_unit.order.adjustments.eligible.non_tax.sum(:amount) * percentage_of_order_total(inventory_unit)
17
+ inventory_unit.order.adjustments.non_tax.sum(:amount) * percentage_of_order_total(inventory_unit)
18
18
  end
19
19
 
20
20
  def weighted_line_item_amount(inventory_unit)
@@ -46,11 +46,11 @@ class Spree::Carton < Spree::Base
46
46
  end
47
47
 
48
48
  def manifest
49
- @manifest ||= Spree::ShippingManifest.new(inventory_units: inventory_units).items
49
+ @manifest ||= Spree::ShippingManifest.new(inventory_units:).items
50
50
  end
51
51
 
52
52
  def manifest_for_order(order)
53
- Spree::ShippingManifest.new(inventory_units: inventory_units).for_order(order).items
53
+ Spree::ShippingManifest.new(inventory_units:).for_order(order).items
54
54
  end
55
55
 
56
56
  def any_exchanges?
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Core
5
+ class StateMachines
6
+ # Inventory Units' state machine
7
+ #
8
+ # for each event the following instance methods are dynamically implemented:
9
+ # #<event_name>
10
+ # #<event_name>!
11
+ # #can_<event_name>?
12
+ #
13
+ # for each state the following instance methods are implemented:
14
+ # #<state_name>?
15
+ #
16
+ module InventoryUnit
17
+ extend ActiveSupport::Concern
18
+
19
+ included do
20
+ state_machine initial: :on_hand do
21
+ event :fill_backorder do
22
+ transition to: :on_hand, from: :backordered
23
+ end
24
+ after_transition on: :fill_backorder, do: :fulfill_order
25
+
26
+ event :ship do
27
+ transition to: :shipped, if: :allow_ship?
28
+ end
29
+
30
+ event :return do
31
+ transition to: :returned, from: :shipped
32
+ end
33
+
34
+ event :cancel do
35
+ transition to: :canceled, from: ::Spree::InventoryUnit::CANCELABLE_STATES.map(&:to_sym)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Core
5
+ class StateMachines
6
+ module Order
7
+ module ClassMethods
8
+ attr_accessor :previous_states
9
+ attr_writer :next_event_transitions, :checkout_steps, :removed_transitions
10
+
11
+ def checkout_flow(&block)
12
+ if block_given?
13
+ @checkout_flow = block
14
+ define_state_machine!
15
+ else
16
+ @checkout_flow
17
+ end
18
+ end
19
+
20
+ def define_state_machine!
21
+ self.checkout_steps = {}
22
+ self.next_event_transitions = []
23
+ self.previous_states = [:cart]
24
+ self.removed_transitions = []
25
+
26
+ # Build the checkout flow using the checkout_flow defined either
27
+ # within the Order class, or a decorator for that class.
28
+ #
29
+ # This method may be called multiple times depending on if the
30
+ # checkout_flow is re-defined in a decorator or not.
31
+ instance_eval(&checkout_flow)
32
+
33
+ klass = self
34
+
35
+ # To avoid multiple occurrences of the same transition being defined
36
+ # On first definition, state_machines will not be defined
37
+ state_machines.clear if respond_to?(:state_machines)
38
+ state_machine :state, initial: :cart, use_transactions: false do
39
+ klass.next_event_transitions.each { |state| transition(state.merge(on: :next)) }
40
+
41
+ # Persist the state on the order
42
+ after_transition do |order, transition|
43
+ # Hard to say if this is really necessary, it was introduced in this commit:
44
+ # https://github.com/mamhoff/solidus/commit/fa1d66c42e4c04ee7cd1c20d87e4cdb74a226d3d
45
+ # But it seems to be harmless, so we'll keep it for now.
46
+ order.state = order.state # rubocop:disable Lint/SelfAssignment
47
+
48
+ order.state_changes.create(
49
+ previous_state: transition.from,
50
+ next_state: transition.to,
51
+ name: 'order',
52
+ user_id: order.user_id
53
+ )
54
+ order.save
55
+ end
56
+
57
+ event :cancel do
58
+ transition to: :canceled, if: :allow_cancel?, from: :complete
59
+ end
60
+
61
+ event :return do
62
+ transition to: :returned, from: [:complete, :awaiting_return], if: :all_inventory_units_returned?
63
+ end
64
+
65
+ event :resume do
66
+ transition to: :resumed, from: :canceled, if: :canceled?
67
+ end
68
+
69
+ event :authorize_return do
70
+ transition to: :awaiting_return, from: :complete
71
+ end
72
+
73
+ event :complete do
74
+ transition to: :complete, from: klass.checkout_steps.keys.last
75
+ end
76
+
77
+ if states[:payment]
78
+ event :payment_failed do
79
+ transition to: :payment, from: :confirm
80
+ end
81
+
82
+ after_transition to: :complete, do: :add_payment_sources_to_wallet
83
+ before_transition to: :payment, do: :add_default_payment_from_wallet
84
+ before_transition to: :payment, do: :ensure_billing_address
85
+
86
+ before_transition to: :confirm, do: :add_store_credit_payments
87
+
88
+ # see also process_payments_before_complete below which needs to
89
+ # be added in the correct sequence.
90
+ end
91
+
92
+ before_transition from: :cart, do: :ensure_line_items_present
93
+
94
+ if states[:address]
95
+ before_transition to: :address, do: :assign_default_user_addresses
96
+ before_transition from: :address, do: :persist_user_address!
97
+ end
98
+
99
+ if states[:delivery]
100
+ before_transition to: :delivery, do: :ensure_shipping_address
101
+ before_transition to: :delivery, do: :create_proposed_shipments
102
+ before_transition to: :delivery, do: :ensure_available_shipping_rates
103
+ end
104
+
105
+ before_transition to: :resumed, do: :ensure_line_item_variants_are_not_deleted
106
+ before_transition to: :resumed, do: :validate_line_item_availability
107
+
108
+ # Sequence of before_transition to: :complete
109
+ # calls matter so that we do not process payments
110
+ # until validations have passed
111
+ before_transition to: :complete, do: :validate_line_item_availability
112
+ before_transition to: :complete, do: :ensure_promotions_eligible
113
+ before_transition to: :complete, do: :ensure_line_item_variants_are_not_deleted
114
+ before_transition to: :complete, do: :ensure_inventory_units
115
+ if states[:payment]
116
+ before_transition to: :complete, do: :process_payments_before_complete
117
+ end
118
+
119
+ after_transition to: :complete, do: :finalize
120
+ after_transition to: :resumed, do: :after_resume
121
+ after_transition to: :canceled, do: :after_cancel
122
+
123
+ after_transition from: any - :cart, to: any - [:confirm, :complete] do |order|
124
+ order.recalculate
125
+ end
126
+
127
+ after_transition do |order, transition|
128
+ order.logger.debug "Order #{order.number} transitioned from #{transition.from} to #{transition.to} via #{transition.event}"
129
+ end
130
+
131
+ after_failure do |order, transition|
132
+ order.logger.debug "Order #{order.number} halted transition on event #{transition.event} state #{transition.from}: #{order.errors.full_messages.join}"
133
+ end
134
+ end
135
+ end
136
+
137
+ def go_to_state(name, options = {})
138
+ checkout_steps[name] = options
139
+ previous_states.each do |state|
140
+ add_transition({ from: state, to: name }.merge(options))
141
+ end
142
+ if options[:if]
143
+ previous_states << name
144
+ else
145
+ self.previous_states = [name]
146
+ end
147
+ end
148
+
149
+ def insert_checkout_step(name, options = {})
150
+ before = options.delete(:before)
151
+ after = options.delete(:after) unless before
152
+ after = checkout_steps.keys.last unless before || after
153
+
154
+ cloned_steps = checkout_steps.clone
155
+ cloned_removed_transitions = removed_transitions.clone
156
+ checkout_flow do
157
+ cloned_steps.each_pair do |key, value|
158
+ go_to_state(name, options) if key == before
159
+ go_to_state(key, value)
160
+ go_to_state(name, options) if key == after
161
+ end
162
+ cloned_removed_transitions.each do |transition|
163
+ remove_transition(transition)
164
+ end
165
+ end
166
+ end
167
+
168
+ def remove_checkout_step(name)
169
+ cloned_steps = checkout_steps.clone
170
+ cloned_removed_transitions = removed_transitions.clone
171
+ checkout_flow do
172
+ cloned_steps.each_pair do |key, value|
173
+ go_to_state(key, value) unless key == name
174
+ end
175
+ cloned_removed_transitions.each do |transition|
176
+ remove_transition(transition)
177
+ end
178
+ end
179
+ end
180
+
181
+ def remove_transition(options = {})
182
+ removed_transitions << options
183
+ next_event_transitions.delete(find_transition(options))
184
+ end
185
+
186
+ def find_transition(options = {})
187
+ return nil if options.nil? || !options.include?(:from) || !options.include?(:to)
188
+
189
+ next_event_transitions.detect do |transition|
190
+ transition[options[:from].to_sym] == options[:to].to_sym
191
+ end
192
+ end
193
+
194
+ def next_event_transitions
195
+ @next_event_transitions ||= []
196
+ end
197
+
198
+ def checkout_steps
199
+ @checkout_steps ||= {}
200
+ end
201
+
202
+ def checkout_step_names
203
+ checkout_steps.keys
204
+ end
205
+
206
+ def add_transition(options)
207
+ next_event_transitions << { options.delete(:from) => options.delete(:to) }.merge(options)
208
+ end
209
+
210
+ def removed_transitions
211
+ @removed_transitions ||= []
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Core
5
+ class StateMachines
6
+ module Order
7
+ def self.included(klass)
8
+ klass.extend ClassMethods
9
+ end
10
+
11
+ def checkout_steps
12
+ steps = self.class.checkout_steps.each_with_object([]) { |(step, options), checkout_steps|
13
+ next if options.include?(:if) && !options[:if].call(self)
14
+
15
+ checkout_steps << step
16
+ }.map(&:to_s)
17
+ # Ensure there is always a complete step
18
+ steps << "complete" unless steps.include?("complete")
19
+ steps
20
+ end
21
+
22
+ def has_checkout_step?(step)
23
+ step.present? && checkout_steps.include?(step)
24
+ end
25
+
26
+ def passed_checkout_step?(step)
27
+ has_checkout_step?(step) && checkout_step_index(step) < checkout_step_index(state)
28
+ end
29
+
30
+ def checkout_step_index(step)
31
+ checkout_steps.index(step).to_i
32
+ end
33
+
34
+ def can_go_to_state?(state)
35
+ return false unless has_checkout_step?(self.state) && has_checkout_step?(state)
36
+
37
+ checkout_step_index(state) > checkout_step_index(self.state)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end