spree_core 5.3.4 → 5.4.0.beta2

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 (331) hide show
  1. checksums.yaml +4 -4
  2. data/app/finders/spree/orders/find_complete.rb +33 -2
  3. data/app/finders/spree/products/find.rb +1 -28
  4. data/app/finders/spree/stores/find_default.rb +17 -0
  5. data/app/finders/spree/variants/visible_finder.rb +1 -0
  6. data/app/helpers/spree/addresses_helper.rb +1 -2
  7. data/app/helpers/spree/base_helper.rb +6 -58
  8. data/app/mailers/spree/base_mailer.rb +4 -3
  9. data/app/models/concerns/spree/adjustment_source.rb +0 -8
  10. data/app/models/concerns/spree/admin_user_methods.rb +32 -2
  11. data/app/models/concerns/spree/image_methods.rb +4 -0
  12. data/app/models/concerns/spree/metadata.rb +10 -0
  13. data/app/models/concerns/spree/number_as_param.rb +5 -3
  14. data/app/models/concerns/spree/prefixed_id.rb +82 -0
  15. data/app/models/concerns/spree/product_scopes.rb +35 -65
  16. data/app/models/concerns/spree/publishable.rb +47 -47
  17. data/app/models/concerns/spree/{multi_store_resource.rb → store_scoped_resource.rb} +1 -10
  18. data/app/models/concerns/spree/stores/markets.rb +124 -0
  19. data/app/models/concerns/spree/user_methods.rb +7 -7
  20. data/app/models/concerns/spree/user_payment_source.rb +2 -0
  21. data/app/models/concerns/spree/user_roles.rb +1 -0
  22. data/app/models/concerns/spree/vat_price_calculation.rb +2 -2
  23. data/app/models/spree/ability.rb +18 -5
  24. data/app/models/spree/address.rb +33 -2
  25. data/app/models/spree/adjustable/promotion_accumulator.rb +1 -1
  26. data/app/models/spree/adjustment.rb +3 -20
  27. data/app/models/spree/api_key.rb +102 -0
  28. data/app/models/spree/asset.rb +2 -0
  29. data/app/models/spree/authentication/strategies/base_strategy.rb +55 -0
  30. data/app/models/spree/authentication/strategies/email_password_strategy.rb +47 -0
  31. data/app/models/spree/base.rb +1 -0
  32. data/app/models/spree/calculator.rb +2 -0
  33. data/app/models/spree/country.rb +60 -0
  34. data/app/models/spree/coupon_code.rb +2 -0
  35. data/app/models/spree/credit_card.rb +2 -27
  36. data/app/models/spree/current.rb +45 -4
  37. data/app/models/spree/customer_group.rb +2 -0
  38. data/app/models/spree/customer_return.rb +2 -0
  39. data/app/models/spree/digital.rb +2 -0
  40. data/app/models/spree/digital_link.rb +2 -0
  41. data/app/models/spree/export.rb +3 -2
  42. data/app/models/spree/exports/products.rb +0 -6
  43. data/app/models/spree/fulfilment_changer.rb +8 -2
  44. data/app/models/spree/gateway/bogus.rb +69 -9
  45. data/app/models/spree/gateway.rb +0 -3
  46. data/app/models/spree/gateway_customer.rb +2 -0
  47. data/app/models/spree/gift_card.rb +2 -0
  48. data/app/models/spree/gift_card_batch.rb +6 -0
  49. data/app/models/spree/image/configuration/active_storage.rb +0 -2
  50. data/app/models/spree/image.rb +25 -31
  51. data/app/models/spree/import.rb +5 -3
  52. data/app/models/spree/import_mapping.rb +2 -0
  53. data/app/models/spree/import_row.rb +2 -0
  54. data/app/models/spree/import_schemas/customers.rb +21 -0
  55. data/app/models/spree/imports/customers.rb +9 -0
  56. data/app/models/spree/integration.rb +2 -0
  57. data/app/models/spree/inventory_unit.rb +2 -0
  58. data/app/models/spree/invitation.rb +6 -6
  59. data/app/models/spree/legacy_admin_user.rb +31 -0
  60. data/app/models/spree/legacy_user.rb +19 -1
  61. data/app/models/spree/line_item.rb +15 -4
  62. data/app/models/spree/log_entry.rb +10 -5
  63. data/app/models/spree/market.rb +83 -0
  64. data/app/models/spree/market_country.rb +25 -0
  65. data/app/models/spree/metafield.rb +2 -0
  66. data/app/models/spree/metafield_definition.rb +2 -0
  67. data/app/models/spree/newsletter_subscriber.rb +2 -0
  68. data/app/models/spree/option_type.rb +2 -0
  69. data/app/models/spree/option_value.rb +2 -0
  70. data/app/models/spree/order/address_book.rb +2 -1
  71. data/app/models/spree/order/checkout.rb +0 -18
  72. data/app/models/spree/order.rb +93 -56
  73. data/app/models/spree/payment/gateway_options.rb +2 -2
  74. data/app/models/spree/payment/processing.rb +5 -5
  75. data/app/models/spree/payment.rb +7 -2
  76. data/app/models/spree/payment_capture_event.rb +2 -0
  77. data/app/models/spree/payment_connection_error.rb +3 -0
  78. data/app/models/spree/payment_method/check.rb +1 -1
  79. data/app/models/spree/payment_method/store_credit.rb +5 -5
  80. data/app/models/spree/payment_method.rb +59 -1
  81. data/app/models/spree/payment_response.rb +70 -0
  82. data/app/models/spree/payment_session.rb +109 -0
  83. data/app/models/spree/payment_sessions/bogus.rb +4 -0
  84. data/app/models/spree/payment_setup_session.rb +79 -0
  85. data/app/models/spree/payment_source.rb +2 -0
  86. data/app/models/spree/permission_sets/default_customer.rb +19 -5
  87. data/app/models/spree/permission_sets/product_display.rb +0 -2
  88. data/app/models/spree/permission_sets/product_management.rb +0 -2
  89. data/app/models/spree/policy.rb +2 -0
  90. data/app/models/spree/price.rb +26 -2
  91. data/app/models/spree/price_list.rb +2 -0
  92. data/app/models/spree/price_rule.rb +2 -0
  93. data/app/models/spree/price_rules/market_rule.rb +19 -0
  94. data/app/models/spree/product.rb +45 -101
  95. data/app/models/spree/promotion/rules/country.rb +1 -1
  96. data/app/models/spree/promotion.rb +5 -15
  97. data/app/models/spree/promotion_action.rb +2 -0
  98. data/app/models/spree/promotion_category.rb +2 -0
  99. data/app/models/spree/promotion_handler/coupon.rb +3 -3
  100. data/app/models/spree/promotion_rule.rb +2 -0
  101. data/app/models/spree/prototype.rb +2 -3
  102. data/app/models/spree/refund.rb +8 -2
  103. data/app/models/spree/refund_reason.rb +2 -0
  104. data/app/models/spree/reimbursement/credit.rb +2 -0
  105. data/app/models/spree/reimbursement.rb +2 -0
  106. data/app/models/spree/reimbursement_type.rb +2 -0
  107. data/app/models/spree/report.rb +3 -1
  108. data/app/models/spree/return_authorization.rb +2 -0
  109. data/app/models/spree/return_authorization_reason.rb +2 -0
  110. data/app/models/spree/return_item.rb +2 -0
  111. data/app/models/spree/role.rb +2 -0
  112. data/app/models/spree/shipment/emails.rb +1 -0
  113. data/app/models/spree/shipment.rb +11 -1
  114. data/app/models/spree/shipping_category.rb +5 -3
  115. data/app/models/spree/shipping_method.rb +2 -0
  116. data/app/models/spree/shipping_method_category.rb +2 -0
  117. data/app/models/spree/shipping_rate.rb +2 -0
  118. data/app/models/spree/state_change.rb +2 -0
  119. data/app/models/spree/stock_item.rb +2 -0
  120. data/app/models/spree/stock_location.rb +2 -0
  121. data/app/models/spree/stock_movement.rb +2 -0
  122. data/app/models/spree/stock_transfer.rb +2 -1
  123. data/app/models/spree/store.rb +111 -219
  124. data/app/models/spree/store_credit.rb +6 -0
  125. data/app/models/spree/store_credit_category.rb +2 -0
  126. data/app/models/spree/store_credit_event.rb +2 -0
  127. data/app/models/spree/store_credit_type.rb +2 -0
  128. data/app/models/spree/store_product.rb +2 -0
  129. data/app/models/spree/tax_category.rb +3 -11
  130. data/app/models/spree/tax_rate.rb +2 -0
  131. data/app/models/spree/taxon.rb +2 -15
  132. data/app/models/spree/taxon_rule.rb +2 -0
  133. data/app/models/spree/taxonomy.rb +2 -0
  134. data/app/models/spree/user_identity.rb +81 -0
  135. data/app/models/spree/variant.rb +15 -43
  136. data/app/models/spree/webhook_delivery.rb +2 -0
  137. data/app/models/spree/webhook_endpoint.rb +2 -0
  138. data/app/models/spree/wished_item.rb +15 -0
  139. data/app/models/spree/wishlist.rb +2 -8
  140. data/app/models/spree/zone.rb +3 -10
  141. data/app/presenters/spree/filters/price_presenter.rb +1 -0
  142. data/app/presenters/spree/filters/price_range_presenter.rb +1 -0
  143. data/app/presenters/spree/filters/quantified_price_range_presenter.rb +1 -0
  144. data/app/presenters/spree/product_summary_presenter.rb +1 -0
  145. data/app/services/spree/addresses/helper.rb +22 -3
  146. data/app/services/spree/cart/add_item.rb +8 -4
  147. data/app/services/spree/cart/associate.rb +19 -6
  148. data/app/services/spree/cart/create.rb +13 -2
  149. data/app/services/spree/checkout/select_shipping_method.rb +13 -1
  150. data/app/services/spree/classifications/reposition.rb +5 -0
  151. data/app/services/spree/imports/row_processors/customer.rb +70 -0
  152. data/app/services/spree/orders/approve.rb +5 -3
  153. data/app/services/spree/orders/cancel.rb +9 -4
  154. data/app/services/spree/products/duplicator.rb +0 -12
  155. data/app/services/spree/products/prepare_nested_attributes.rb +1 -13
  156. data/app/services/spree/sample_data/import_runner.rb +54 -0
  157. data/app/services/spree/sample_data/loader.rb +78 -0
  158. data/app/services/spree/seeds/admin_user.rb +2 -3
  159. data/app/services/spree/seeds/all.rb +1 -0
  160. data/app/services/spree/seeds/api_keys.rb +16 -0
  161. data/app/services/spree/seeds/stores.rb +2 -4
  162. data/app/sorters/spree/orders/sort.rb +4 -0
  163. data/app/subscribers/spree/product_metrics_subscriber.rb +4 -4
  164. data/config/brakeman.ignore +120 -0
  165. data/config/locales/en.yml +23 -21
  166. data/db/migrate/20210914000000_spree_four_three.rb +0 -38
  167. data/db/migrate/20210915064329_add_metadata_to_spree_multiple_tables.rb +0 -1
  168. data/db/migrate/20250923141900_create_spree_user_identities.rb +17 -0
  169. data/db/migrate/20260123000000_create_spree_api_keys.rb +19 -0
  170. data/db/migrate/20260131000000_add_thumbnail_id_to_spree_variants_and_products.rb +9 -0
  171. data/db/migrate/20260213000000_create_spree_payment_sessions.rb +27 -0
  172. data/db/migrate/20260218000000_create_spree_payment_setup_sessions.rb +24 -0
  173. data/db/migrate/20260220000000_create_spree_markets.rb +29 -0
  174. data/db/migrate/20260226000000_add_locale_to_spree_orders.rb +5 -0
  175. data/db/migrate/20260226100000_add_token_digest_to_spree_api_keys.rb +21 -0
  176. data/db/sample_data/customers.csv +21 -0
  177. data/db/sample_data/metafield_definitions.rb +7 -0
  178. data/db/sample_data/orders.rb +131 -0
  179. data/db/sample_data/payment_methods.rb +17 -0
  180. data/db/sample_data/products.csv +1083 -0
  181. data/db/sample_data/promotions.rb +8 -0
  182. data/db/sample_data/shipping_methods.rb +39 -0
  183. data/lib/generators/spree/authentication/devise/devise_generator.rb +2 -2
  184. data/lib/generators/spree/authentication/dummy/dummy_generator.rb +54 -0
  185. data/lib/generators/spree/authentication/dummy/templates/authentication_helpers.rb.tt +52 -0
  186. data/lib/generators/spree/authentication/dummy/templates/create_spree_admin_users.rb.tt +33 -0
  187. data/lib/generators/spree/cursor_rules/templates/spree_rules.mdc +1 -3
  188. data/lib/generators/spree/dummy/dummy_generator.rb +1 -1
  189. data/lib/spree/core/configuration.rb +1 -3
  190. data/lib/spree/core/controller_helpers/common.rb +6 -0
  191. data/lib/spree/core/controller_helpers/currency.rb +5 -0
  192. data/lib/spree/core/controller_helpers/order.rb +5 -1
  193. data/lib/spree/core/controller_helpers/store.rb +1 -1
  194. data/lib/spree/core/controller_helpers/strong_parameters.rb +1 -2
  195. data/lib/spree/core/dependencies.rb +3 -11
  196. data/lib/spree/core/engine.rb +17 -17
  197. data/lib/spree/core/pricing/context.rb +6 -3
  198. data/lib/spree/core/pricing/resolver.rb +1 -9
  199. data/lib/spree/core/version.rb +1 -1
  200. data/lib/spree/core.rb +14 -29
  201. data/lib/spree/database_type_utilities.rb +7 -0
  202. data/lib/spree/events.rb +17 -10
  203. data/lib/spree/money.rb +2 -9
  204. data/lib/spree/permitted_attributes.rb +20 -20
  205. data/lib/spree/testing_support/capybara_config.rb +2 -2
  206. data/lib/spree/testing_support/common_rake.rb +15 -4
  207. data/lib/spree/testing_support/factories/api_key_factory.rb +19 -0
  208. data/lib/spree/testing_support/factories/custom_domain_factory.rb +7 -5
  209. data/lib/spree/testing_support/factories/import_factory.rb +12 -0
  210. data/lib/spree/testing_support/factories/market_factory.rb +35 -0
  211. data/lib/spree/testing_support/factories/order_factory.rb +4 -1
  212. data/lib/spree/testing_support/factories/payment_method_factory.rb +3 -6
  213. data/lib/spree/testing_support/factories/payment_session_factory.rb +47 -0
  214. data/lib/spree/testing_support/factories/payment_setup_session_factory.rb +31 -0
  215. data/lib/spree/testing_support/factories/price_rule_factory.rb +10 -0
  216. data/lib/spree/testing_support/factories/product_factory.rb +0 -7
  217. data/lib/spree/testing_support/factories/prototype_factory.rb +0 -2
  218. data/lib/spree/testing_support/factories/user_identity_factory.rb +15 -0
  219. data/lib/spree/testing_support/store.rb +3 -2
  220. data/lib/spree/webhooks.rb +7 -7
  221. data/lib/tasks/core.rake +0 -265
  222. data/lib/tasks/images.rake +20 -0
  223. data/lib/tasks/markets.rake +40 -0
  224. data/lib/tasks/sample_data.rake +15 -0
  225. data/spec/fixtures/files/customers_import.csv +4 -0
  226. metadata +101 -154
  227. data/LICENSE.md +0 -57
  228. data/app/finders/spree/posts/find.rb +0 -137
  229. data/app/finders/spree/product_properties/find_available.rb +0 -20
  230. data/app/finders/spree/stores/find_current.rb +0 -28
  231. data/app/helpers/spree/mail_helper.rb +0 -27
  232. data/app/mailers/spree/test_mailer.rb +0 -8
  233. data/app/models/action_text/video_embed.rb +0 -13
  234. data/app/models/concerns/spree/has_one_link.rb +0 -42
  235. data/app/models/concerns/spree/linkable.rb +0 -9
  236. data/app/models/concerns/spree/previewable.rb +0 -17
  237. data/app/models/spree/custom_domain.rb +0 -59
  238. data/app/models/spree/data_feed/google.rb +0 -15
  239. data/app/models/spree/data_feed.rb +0 -40
  240. data/app/models/spree/gateway/bogus_simple.rb +0 -24
  241. data/app/models/spree/post.rb +0 -106
  242. data/app/models/spree/post_category.rb +0 -44
  243. data/app/models/spree/product_property.rb +0 -51
  244. data/app/models/spree/property.rb +0 -86
  245. data/app/models/spree/property_prototype.rb +0 -9
  246. data/app/models/spree/store_favicon_image.rb +0 -20
  247. data/app/models/spree/store_logo.rb +0 -4
  248. data/app/models/spree/store_mailer_logo.rb +0 -7
  249. data/app/models/spree/taxon_image/configuration/active_storage.rb +0 -26
  250. data/app/models/spree/taxon_image.rb +0 -20
  251. data/app/presenters/spree/filters/properties_presenter.rb +0 -23
  252. data/app/presenters/spree/filters/property_presenter.rb +0 -42
  253. data/app/serializers/spree/events/asset_serializer.rb +0 -22
  254. data/app/serializers/spree/events/base_serializer.rb +0 -61
  255. data/app/serializers/spree/events/customer_return_serializer.rb +0 -20
  256. data/app/serializers/spree/events/digital_link_serializer.rb +0 -20
  257. data/app/serializers/spree/events/digital_serializer.rb +0 -18
  258. data/app/serializers/spree/events/export_serializer.rb +0 -22
  259. data/app/serializers/spree/events/gift_card_batch_serializer.rb +0 -24
  260. data/app/serializers/spree/events/gift_card_serializer.rb +0 -29
  261. data/app/serializers/spree/events/image_serializer.rb +0 -9
  262. data/app/serializers/spree/events/import_row_serializer.rb +0 -23
  263. data/app/serializers/spree/events/import_serializer.rb +0 -24
  264. data/app/serializers/spree/events/invitation_serializer.rb +0 -28
  265. data/app/serializers/spree/events/line_item_serializer.rb +0 -31
  266. data/app/serializers/spree/events/newsletter_subscriber_serializer.rb +0 -21
  267. data/app/serializers/spree/events/order_serializer.rb +0 -39
  268. data/app/serializers/spree/events/payment_serializer.rb +0 -24
  269. data/app/serializers/spree/events/post_category_serializer.rb +0 -20
  270. data/app/serializers/spree/events/post_serializer.rb +0 -26
  271. data/app/serializers/spree/events/price_serializer.rb +0 -22
  272. data/app/serializers/spree/events/product_serializer.rb +0 -24
  273. data/app/serializers/spree/events/promotion_serializer.rb +0 -32
  274. data/app/serializers/spree/events/refund_serializer.rb +0 -23
  275. data/app/serializers/spree/events/reimbursement_serializer.rb +0 -22
  276. data/app/serializers/spree/events/report_serializer.rb +0 -23
  277. data/app/serializers/spree/events/return_authorization_serializer.rb +0 -22
  278. data/app/serializers/spree/events/return_item_serializer.rb +0 -27
  279. data/app/serializers/spree/events/shipment_serializer.rb +0 -24
  280. data/app/serializers/spree/events/stock_item_serializer.rb +0 -22
  281. data/app/serializers/spree/events/stock_movement_serializer.rb +0 -22
  282. data/app/serializers/spree/events/stock_transfer_serializer.rb +0 -22
  283. data/app/serializers/spree/events/store_credit_serializer.rb +0 -30
  284. data/app/serializers/spree/events/user_serializer.rb +0 -18
  285. data/app/serializers/spree/events/variant_serializer.rb +0 -34
  286. data/app/serializers/spree/events/wished_item_serializer.rb +0 -20
  287. data/app/serializers/spree/events/wishlist_serializer.rb +0 -22
  288. data/app/services/spree/data_feeds/google/optional_attributes.rb +0 -23
  289. data/app/services/spree/data_feeds/google/optional_sub_attributes.rb +0 -21
  290. data/app/services/spree/data_feeds/google/products_list.rb +0 -14
  291. data/app/services/spree/data_feeds/google/required_attributes.rb +0 -68
  292. data/app/services/spree/data_feeds/google/rss.rb +0 -109
  293. data/app/sorters/spree/posts/sort.rb +0 -40
  294. data/app/views/action_text/video_embeds/_thumbnail.html.erb +0 -1
  295. data/app/views/action_text/video_embeds/_video_embed.html.erb +0 -3
  296. data/app/views/layouts/action_text/contents/_content.html.erb +0 -3
  297. data/app/views/spree/test_mailer/test_email.html.erb +0 -40
  298. data/app/views/spree/test_mailer/test_email.text.erb +0 -4
  299. data/config/initializers/oembed.rb +0 -1
  300. data/db/migrate/20221229132350_create_spree_data_feed_settings.rb +0 -14
  301. data/db/migrate/20230109084253_create_product_property_translations.rb +0 -24
  302. data/db/migrate/20230109105943_create_property_translations.rb +0 -24
  303. data/db/migrate/20230415155958_rename_data_feed_settings_table.rb +0 -5
  304. data/db/migrate/20230415160828_rename_data_feed_table_columns.rb +0 -7
  305. data/db/migrate/20230415161226_add_indexes_to_data_feeds_table.rb +0 -5
  306. data/db/migrate/20230512094803_rename_data_feeds_column_provider_to_type.rb +0 -5
  307. data/db/migrate/20240914153106_add_display_on_to_spree_properties.rb +0 -5
  308. data/db/migrate/20240915144935_add_position_to_spree_properties.rb +0 -6
  309. data/db/migrate/20250121160028_create_spree_posts_and_spree_post_categories.rb +0 -33
  310. data/db/migrate/20250127083740_add_kind_to_spree_properties.rb +0 -5
  311. data/db/migrate/20250217171018_create_action_text_video_embeds.rb +0 -11
  312. data/db/migrate/20250305121657_remove_spree_posts_indices.rb +0 -7
  313. data/db/migrate/20250730154601_add_unique_index_on_spree_properties_name.rb +0 -24
  314. data/lib/spree/core/controller_helpers/search.rb +0 -17
  315. data/lib/spree/core/product_filters.rb +0 -204
  316. data/lib/spree/core/query_filters/comparable.rb +0 -46
  317. data/lib/spree/core/query_filters/date.rb +0 -8
  318. data/lib/spree/core/query_filters/number.rb +0 -8
  319. data/lib/spree/core/query_filters/text.rb +0 -32
  320. data/lib/spree/core/query_filters.rb +0 -11
  321. data/lib/spree/core/search/base.rb +0 -144
  322. data/lib/spree/testing_support/factories/favicon_image_factory.rb +0 -9
  323. data/lib/spree/testing_support/factories/google_data_feed_factory.rb +0 -7
  324. data/lib/spree/testing_support/factories/post_category_factory.rb +0 -7
  325. data/lib/spree/testing_support/factories/post_factory.rb +0 -22
  326. data/lib/spree/testing_support/factories/product_property_factory.rb +0 -7
  327. data/lib/spree/testing_support/factories/property_factory.rb +0 -28
  328. data/lib/spree/testing_support/factories/taxon_image_factory.rb +0 -9
  329. data/lib/spree/testing_support/flash.rb +0 -25
  330. data/lib/spree/testing_support/flatpickr_capybara.rb +0 -124
  331. data/lib/tasks/exchanges.rake +0 -66
@@ -0,0 +1,79 @@
1
+ module Spree
2
+ class PaymentSetupSession < Spree.base_class
3
+ has_prefix_id :pss
4
+
5
+ acts_as_paranoid
6
+
7
+ include Spree::Metafields
8
+
9
+ self.event_prefix = 'payment_setup_session'
10
+
11
+ publishes_lifecycle_events
12
+
13
+ belongs_to :customer, class_name: Spree.user_class.to_s, optional: true
14
+ belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
15
+ belongs_to :payment_source, polymorphic: true, optional: true
16
+
17
+ validates :payment_method, :status, presence: true
18
+ validates :external_id, uniqueness: { scope: :payment_method_id }, allow_nil: true
19
+
20
+ state_machine :status, initial: :pending do
21
+ state :pending
22
+ state :processing
23
+ state :completed
24
+ state :failed
25
+ state :canceled
26
+ state :expired
27
+
28
+ event :process do
29
+ transition pending: :processing
30
+ end
31
+
32
+ event :complete do
33
+ transition [:pending, :processing] => :completed
34
+ end
35
+
36
+ event :fail do
37
+ transition [:pending, :processing] => :failed
38
+ end
39
+
40
+ event :cancel do
41
+ transition [:pending, :processing] => :canceled
42
+ end
43
+
44
+ event :expire do
45
+ transition [:pending, :processing] => :expired
46
+ end
47
+
48
+ after_transition to: :processing, do: :publish_processing_event
49
+ after_transition to: :completed, do: :publish_completed_event
50
+ after_transition to: :failed, do: :publish_failed_event
51
+ after_transition to: :canceled, do: :publish_canceled_event
52
+ after_transition to: :expired, do: :publish_expired_event
53
+ end
54
+
55
+ scope :active, -> { where(status: %w[pending processing]) }
56
+
57
+ private
58
+
59
+ def publish_processing_event
60
+ publish_event('payment_setup_session.processing')
61
+ end
62
+
63
+ def publish_completed_event
64
+ publish_event('payment_setup_session.completed')
65
+ end
66
+
67
+ def publish_failed_event
68
+ publish_event('payment_setup_session.failed')
69
+ end
70
+
71
+ def publish_canceled_event
72
+ publish_event('payment_setup_session.canceled')
73
+ end
74
+
75
+ def publish_expired_event
76
+ publish_event('payment_setup_session.expired')
77
+ end
78
+ end
79
+ end
@@ -1,6 +1,8 @@
1
1
  # This model is used to store payment sources for non-credit card payments, eg wallet, account, etc.
2
2
  module Spree
3
3
  class PaymentSource < Spree.base_class
4
+ has_prefix_id :ps
5
+
4
6
  include Spree::Metafields
5
7
  include Spree::Metadata
6
8
  include Spree::PaymentSourceConcern
@@ -15,8 +15,6 @@ module Spree
15
15
  can :read, Spree::OptionType
16
16
  can :read, Spree::OptionValue
17
17
  can :read, Spree::Product
18
- can :read, Spree::ProductProperty
19
- can :read, Spree::Property
20
18
  can :read, Spree::State
21
19
  can :read, Spree::Store
22
20
  can :read, Spree::Taxon
@@ -26,9 +24,6 @@ module Spree
26
24
 
27
25
  # Content pages
28
26
  can :read, Spree::Policy
29
- can :read, Spree::Page if defined?(Spree::Page)
30
- can :read, Spree::Post if defined?(Spree::Post)
31
- can :read, Spree::PostCategory if defined?(Spree::PostCategory)
32
27
 
33
28
  # Order management for the user's own orders
34
29
  can :create, Spree::Order
@@ -39,6 +34,17 @@ module Spree
39
34
  !order.completed? && (order.user == user || order.token && token == order.token)
40
35
  end
41
36
 
37
+ # Line item management
38
+ can :create, Spree::LineItem do |line_item, token|
39
+ line_item.order.user == user || line_item.order.token && token == line_item.order.token
40
+ end
41
+ can :update, Spree::LineItem do |line_item, token|
42
+ !line_item.order.completed? && (line_item.order.user == user || line_item.order.token && token == line_item.order.token)
43
+ end
44
+ can :destroy, Spree::LineItem do |line_item, token|
45
+ !line_item.order.completed? && (line_item.order.user == user || line_item.order.token && token == line_item.order.token)
46
+ end
47
+
42
48
  # User account management - available to all users (including guests for their own record)
43
49
  can :create, Spree.user_class
44
50
  can [:show, :update, :destroy], Spree.user_class, id: user.id
@@ -49,6 +55,9 @@ module Spree
49
55
  # Credit card management
50
56
  can [:read, :destroy], Spree::CreditCard, user_id: user.id
51
57
 
58
+ # Gift card management - users can view their own gift cards
59
+ can :read, Spree::GiftCard, user_id: user.id
60
+
52
61
  # Wishlist management
53
62
  can :manage, Spree::Wishlist, user_id: user.id
54
63
  can :show, Spree::Wishlist do |wishlist|
@@ -60,6 +69,11 @@ module Spree
60
69
 
61
70
  # Invitation acceptance
62
71
  can :accept, Spree::Invitation, invitee_id: [user.id, nil], invitee_type: user.class.name, status: 'pending'
72
+
73
+ # Digital downloads - token-based access
74
+ can :show, Spree::DigitalLink do |digital_link, token|
75
+ digital_link.token == token
76
+ end
63
77
  end
64
78
  end
65
79
  end
@@ -14,8 +14,6 @@ module Spree
14
14
  can [:read, :admin], Spree::Variant
15
15
  can [:read, :admin], Spree::OptionType
16
16
  can [:read, :admin], Spree::OptionValue
17
- can [:read, :admin], Spree::Property
18
- can [:read, :admin], Spree::ProductProperty
19
17
  can [:read, :admin], Spree::Metafield
20
18
  can [:read, :admin], Spree::Taxon
21
19
  can [:read, :admin], Spree::Taxonomy
@@ -14,8 +14,6 @@ module Spree
14
14
  can :manage, Spree::Variant
15
15
  can :manage, Spree::OptionType
16
16
  can :manage, Spree::OptionValue
17
- can :manage, Spree::Property
18
- can :manage, Spree::ProductProperty
19
17
  can :manage, Spree::Taxon
20
18
  can :manage, Spree::Taxonomy
21
19
  can :manage, Spree::Classification
@@ -1,5 +1,7 @@
1
1
  module Spree
2
2
  class Policy < Spree.base_class
3
+ has_prefix_id :pol
4
+
3
5
  extend FriendlyId
4
6
  include Spree::TranslatableResource
5
7
 
@@ -1,5 +1,7 @@
1
1
  module Spree
2
2
  class Price < Spree.base_class
3
+ has_prefix_id :price
4
+
3
5
  include Spree::VatPriceCalculation
4
6
 
5
7
  publishes_lifecycle_events
@@ -38,13 +40,13 @@ module Spree
38
40
  scope :discounted, -> { where('compare_at_amount > amount') }
39
41
  scope :base_prices, -> { where(price_list_id: nil) }
40
42
  scope :for_price_list, ->(price_list) { where(price_list_id: price_list) }
41
- scope :for_products, ->(products, currency = nil) do
43
+ scope :for_products, lambda { |products, currency = nil|
42
44
  currency ||= Spree::Store.default.default_currency
43
45
 
44
46
  with_currency(currency).joins(:variant).where(
45
47
  Spree::Variant.table_name => { product_id: products }
46
48
  )
47
- end
49
+ }
48
50
 
49
51
  extend DisplayMoney
50
52
  money_methods :amount, :price, :compare_at_amount
@@ -64,6 +66,12 @@ module Spree
64
66
  self[:amount] = amount.blank? ? nil : Spree::LocalizedNumber.parse(amount)
65
67
  end
66
68
 
69
+ # Returns the amount in cents
70
+ # @return [Integer]
71
+ def amount_in_cents
72
+ display_amount&.amount_in_cents
73
+ end
74
+
67
75
  def compare_at_money
68
76
  Spree::Money.new(compare_at_amount || 0, currency: currency)
69
77
  end
@@ -74,6 +82,22 @@ module Spree
74
82
  self[:compare_at_amount] = calculated_value
75
83
  end
76
84
 
85
+ # Returns the compare at amount for display
86
+ # @return [Spree::Money, nil]
87
+ def display_compare_at_amount
88
+ return nil if compare_at_amount.nil?
89
+
90
+ Spree::Money.new(compare_at_amount, currency: currency)
91
+ end
92
+
93
+ # Returns the compare at amount in cents
94
+ # @return [Integer, nil]
95
+ def compare_at_amount_in_cents
96
+ return nil if compare_at_amount.nil?
97
+
98
+ display_compare_at_amount.amount_in_cents
99
+ end
100
+
77
101
  alias_attribute :price, :amount
78
102
  alias_method :price=, :amount=
79
103
  alias_attribute :compare_at_price, :compare_at_amount
@@ -1,5 +1,7 @@
1
1
  module Spree
2
2
  class PriceList < Spree.base_class
3
+ has_prefix_id :pl
4
+
3
5
  acts_as_paranoid
4
6
  acts_as_list scope: :store_id
5
7
 
@@ -1,5 +1,7 @@
1
1
  module Spree
2
2
  class PriceRule < Spree.base_class
3
+ has_prefix_id :prule
4
+
3
5
  belongs_to :price_list, class_name: 'Spree::PriceList', touch: true
4
6
 
5
7
  validates :type, :price_list,presence: true
@@ -0,0 +1,19 @@
1
+ module Spree
2
+ module PriceRules
3
+ class MarketRule < Spree::PriceRule
4
+ preference :market_ids, :array, default: []
5
+
6
+ def applicable?(context)
7
+ return false unless context.market
8
+ return true if preferred_market_ids.empty?
9
+
10
+ # Compare as strings to support both integer and UUID primary keys
11
+ preferred_market_ids.map(&:to_s).include?(context.market.id.to_s)
12
+ end
13
+
14
+ def self.description
15
+ 'Apply pricing based on the market'
16
+ end
17
+ end
18
+ end
19
+ end
@@ -20,12 +20,14 @@
20
20
 
21
21
  module Spree
22
22
  class Product < Spree.base_class
23
+ has_prefix_id :prod # Stripe: prod_
24
+
23
25
  acts_as_paranoid
24
26
  acts_as_taggable_on :tags, :labels
25
27
  normalizes :name, with: ->(value) { value&.to_s&.squish&.presence }
26
28
 
27
29
  include Spree::ProductScopes
28
- include Spree::MultiStoreResource
30
+ include Spree::StoreScopedResource
29
31
  include Spree::TranslatableResource
30
32
  include Spree::MemoizedData
31
33
  include Spree::Metafields
@@ -70,9 +72,6 @@ module Spree
70
72
 
71
73
  has_many :product_option_types, -> { order(:position) }, dependent: :destroy, inverse_of: :product
72
74
  has_many :option_types, through: :product_option_types
73
- has_many :product_properties, dependent: :destroy, inverse_of: :product
74
- has_many :properties, through: :product_properties
75
-
76
75
  has_many :classifications, -> { order(created_at: :asc) }, dependent: :delete_all, inverse_of: :product
77
76
  has_many :taxons, through: :classifications, before_remove: :remove_taxon
78
77
  has_many :taxonomies, through: :taxons
@@ -117,6 +116,8 @@ module Spree
117
116
  has_many :variant_images, -> { order(:position) }, source: :images, through: :variants_including_master
118
117
  has_many :variant_images_without_master, -> { order(:position) }, source: :images, through: :variants
119
118
 
119
+ belongs_to :thumbnail, class_name: 'Spree::Image', optional: true
120
+
120
121
  has_many :option_value_variants, class_name: 'Spree::OptionValueVariant', through: :variants
121
122
  has_many :option_values, class_name: 'Spree::OptionValue', through: :variants
122
123
 
@@ -211,9 +212,6 @@ module Spree
211
212
 
212
213
  attr_accessor :option_values_hash
213
214
 
214
- accepts_nested_attributes_for :product_properties, allow_destroy: true, reject_if: lambda { |pp|
215
- pp[:property_id].blank? || (pp[:id].blank? && pp[:value].blank?)
216
- }
217
215
  accepts_nested_attributes_for(
218
216
  :variants,
219
217
  allow_destroy: true,
@@ -230,11 +228,12 @@ module Spree
230
228
 
231
229
  alias options product_option_types
232
230
 
233
- self.whitelisted_ransackable_attributes = %w[description name slug discontinue_on status]
231
+ self.whitelisted_ransackable_attributes = %w[description name slug discontinue_on status available_on created_at updated_at]
234
232
  self.whitelisted_ransackable_associations = %w[taxons stores variants_including_master master variants tags labels
235
- shipping_category classifications option_types properties]
233
+ shipping_category classifications option_types]
236
234
  self.whitelisted_ransackable_scopes = %w[not_discontinued search_by_name in_taxon price_between
237
- multi_search in_stock_items out_of_stock_items]
235
+ multi_search in_stock_items out_of_stock_items with_option_value_ids
236
+ ascend_by_price descend_by_price]
238
237
 
239
238
  [
240
239
  :sku, :barcode, :weight, :height, :width, :depth, :is_master, :dimensions_unit, :weight_unit
@@ -252,6 +251,9 @@ module Spree
252
251
  delegate :display_amount, :display_price, :has_default_price?, :track_inventory?,
253
252
  :display_compare_at_price, :images, to: :default_variant
254
253
 
254
+ # Rails doesn't provide _id methods for has_one associations by default
255
+ delegate :id, to: :master, prefix: true, allow_nil: true
256
+
255
257
  alias master_images images
256
258
 
257
259
  state_machine :status, initial: :draft do
@@ -290,12 +292,12 @@ module Spree
290
292
 
291
293
  # Can't use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259
292
294
  def purchasable?
293
- @purchasable ||= default_variant.purchasable? || variants.in_stock_or_backorderable.any?
295
+ @purchasable ||= default_variant.purchasable? || variants.any?(&:purchasable?)
294
296
  end
295
297
 
296
298
  # Can't use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259
297
299
  def in_stock?
298
- @in_stock ||= default_variant.in_stock? || variants.in_stock.any?
300
+ @in_stock ||= default_variant.in_stock? || variants.any?(&:in_stock?)
299
301
  end
300
302
 
301
303
  # Can't use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259
@@ -362,9 +364,10 @@ module Spree
362
364
  end
363
365
 
364
366
  # Returns default Image for Product.
367
+ # Uses cached thumbnail_id which is updated when images are added/removed/reordered.
365
368
  # @return [Spree::Image, nil]
366
369
  def default_image
367
- variant_for_images&.primary_image
370
+ thumbnail
368
371
  end
369
372
 
370
373
  # Backward compatibility for Spree 5.2 and earlier.
@@ -390,6 +393,13 @@ module Spree
390
393
  variant_for_images&.image_count || 0
391
394
  end
392
395
 
396
+ # Updates the thumbnail_id to the first image from variant_images.
397
+ # Called when images are added, removed, or reordered on any variant.
398
+ def update_thumbnail!
399
+ first_image = variant_images.order(:position).first
400
+ update_column(:thumbnail_id, first_image&.id)
401
+ end
402
+
393
403
  # Finds first variant with images using preloaded data when available.
394
404
  # @return [Spree::Variant, nil]
395
405
  def find_variant_with_images
@@ -401,7 +411,7 @@ module Spree
401
411
  # Returns the short description for the product
402
412
  # @return [String]
403
413
  def storefront_description
404
- property('short_description') || description
414
+ description
405
415
  end
406
416
 
407
417
  # Returns tax category for Product
@@ -463,13 +473,6 @@ module Spree
463
473
  Products::Duplicator.call(product: self)
464
474
  end
465
475
 
466
- # use deleted? rather than checking the attribute directly. this
467
- # allows extensions to override deleted? if they want to provide
468
- # their own definition.
469
- def deleted?
470
- !!deleted_at
471
- end
472
-
473
476
  # determine if product is available.
474
477
  # deleted products and products with status different than active
475
478
  # are not available
@@ -497,14 +500,6 @@ module Spree
497
500
  variants_including_master.any?(&:backordered?)
498
501
  end
499
502
 
500
- # split variants list into hash which shows mapping of opt value onto matching variants
501
- # eg categorise_variants_from_option(color) => {"red" -> [...], "blue" -> [...]}
502
- def categorise_variants_from_option(opt_type)
503
- return {} unless option_types.include?(opt_type)
504
-
505
- variants.active.group_by { |v| v.option_values.detect { |o| o.option_type == opt_type } }
506
- end
507
-
508
503
  def self.like_any(fields, values)
509
504
  conditions = fields.product(values).map do |(field, value)|
510
505
  arel_table[field].matches("%#{value}%")
@@ -521,48 +516,6 @@ module Spree
521
516
  variants.active(current_currency).joins(:option_value_variants)
522
517
  end
523
518
 
524
- def empty_option_values?
525
- options.empty? || options.any? do |opt|
526
- opt.option_type.option_values.empty?
527
- end
528
- end
529
-
530
- def property(property_name)
531
- if product_properties.loaded?
532
- product_properties.detect { |property| property.property.name == property_name }.try(:value)
533
- else
534
- product_properties.joins(:property).find_by(spree_properties: { name: property_name }).try(:value)
535
- end
536
- end
537
-
538
- def set_property(property_name, property_value, property_presentation = property_name)
539
- property_name = property_name.to_s.parameterize
540
- ApplicationRecord.transaction do
541
- # Manual first_or_create to work around Mobility bug
542
- property = if Property.where(name: property_name).exists?
543
- existing_property = Property.where(name: property_name).first
544
- existing_property.presentation ||= property_presentation
545
- existing_property.save
546
- existing_property
547
- else
548
- Property.create(name: property_name, presentation: property_presentation)
549
- end
550
-
551
- product_property = if ProductProperty.where(product: self, property: property).exists?
552
- ProductProperty.where(product: self, property: property).first
553
- else
554
- ProductProperty.new(product: self, property: property)
555
- end
556
-
557
- product_property.value = property_value
558
- product_property.save!
559
- end
560
- end
561
-
562
- def remove_property(property_name)
563
- product_properties.joins(:property).find_by(spree_properties: { name: property_name.parameterize })&.destroy
564
- end
565
-
566
519
  def total_on_hand
567
520
  @total_on_hand ||= if any_variants_not_track_inventory?
568
521
  BigDecimal::INFINITY
@@ -598,15 +551,13 @@ module Spree
598
551
  nil
599
552
  elsif Spree.use_translations?
600
553
  taxons.joins(:taxonomy).
601
- join_translation_table(Taxonomy).
602
- find_by(Taxonomy.translation_table_alias => { name: Spree.t(:taxonomy_brands_name) })
603
- else
604
- if taxons.loaded?
605
- taxons.find { |taxon| taxon.taxonomy.name == Spree.t(:taxonomy_brands_name) }
606
- else
607
- taxons.joins(:taxonomy).find_by(Taxonomy.table_name => { name: Spree.t(:taxonomy_brands_name) })
608
- end
609
- end
554
+ join_translation_table(Taxonomy).
555
+ find_by(Taxonomy.translation_table_alias => { name: Spree.t(:taxonomy_brands_name) })
556
+ elsif taxons.loaded?
557
+ taxons.find { |taxon| taxon.taxonomy.name == Spree.t(:taxonomy_brands_name) }
558
+ else
559
+ taxons.joins(:taxonomy).find_by(Taxonomy.table_name => { name: Spree.t(:taxonomy_brands_name) })
560
+ end
610
561
  end
611
562
 
612
563
  # Returns the brand name for the product
@@ -638,12 +589,10 @@ module Spree
638
589
  join_translation_table(Taxonomy).
639
590
  order(depth: :desc).
640
591
  find_by(Taxonomy.translation_table_alias => { name: Spree.t(:taxonomy_categories_name) })
592
+ elsif taxons.loaded?
593
+ taxons.find { |taxon| taxon.taxonomy.name == Spree.t(:taxonomy_categories_name) }
641
594
  else
642
- if taxons.loaded?
643
- taxons.find { |taxon| taxon.taxonomy.name == Spree.t(:taxonomy_categories_name) }
644
- else
645
- taxons.joins(:taxonomy).order(depth: :desc).find_by(Taxonomy.table_name => { name: Spree.t(:taxonomy_categories_name) })
646
- end
595
+ taxons.joins(:taxonomy).order(depth: :desc).find_by(Taxonomy.table_name => { name: Spree.t(:taxonomy_categories_name) })
647
596
  end
648
597
  end
649
598
 
@@ -656,9 +605,7 @@ module Spree
656
605
  def taxons_for_store(store)
657
606
  return if classification_count.zero?
658
607
 
659
- Rails.cache.fetch("#{cache_key_with_version}/taxons-per-store/#{store.id}") do
660
- taxons.loaded? ? taxons.find_all { |taxon| taxon.taxonomy.store_id == store.id } : taxons.for_store(store)
661
- end
608
+ taxons.loaded? ? taxons.find_all { |taxon| taxon.taxonomy.store_id == store.id } : taxons.for_store(store)
662
609
  end
663
610
 
664
611
  def any_variant_in_stock_or_backorderable?
@@ -690,16 +637,16 @@ module Spree
690
637
 
691
638
  def to_csv(store = nil)
692
639
  store ||= stores.default || stores.first
693
- properties_for_csv = if Spree::Config[:product_properties_enabled]
694
- Spree::Property.order(:position).flat_map do |property|
695
- [
696
- property.name,
697
- product_properties.find { |pp| pp.property_id == property.id }&.value
698
- ]
699
- end
700
- else
701
- []
702
- end
640
+ properties_for_csv = if respond_to?(:product_properties) && Spree::Config.respond_to?(:product_properties_enabled) && Spree::Config[:product_properties_enabled]
641
+ Spree::Property.order(:position).flat_map do |property|
642
+ [
643
+ property.name,
644
+ product_properties.find { |pp| pp.property_id == property.id }&.value
645
+ ]
646
+ end
647
+ else
648
+ []
649
+ end
703
650
  metafields_for_csv ||= Spree::MetafieldDefinition.for_resource_type('Spree::Product').order(:namespace, :key).map do |mf_def|
704
651
  metafields.find { |mf| mf.metafield_definition_id == mf_def.id }&.csv_value
705
652
  end
@@ -734,9 +681,6 @@ module Spree
734
681
 
735
682
  def add_associations_from_prototype
736
683
  if prototype_id && prototype = Spree::Prototype.find_by(id: prototype_id)
737
- prototype.properties.each do |property|
738
- product_properties.create(property: property, value: 'Placeholder')
739
- end
740
684
  self.option_types = prototype.option_types
741
685
  self.taxons = prototype.taxons
742
686
  end
@@ -30,7 +30,7 @@ module Spree
30
30
 
31
31
  def validate_eligibility_by_country_iso(order)
32
32
  country_iso = order.ship_address&.country_iso
33
- return true if country_iso == (preferred_country_iso || order.store.default_country_iso)
33
+ return true if country_iso == (preferred_country_iso || order.store.default_market&.default_country&.iso)
34
34
 
35
35
  eligibility_errors.add(:base, eligibility_error_message(:wrong_country))
36
36
  false
@@ -1,6 +1,8 @@
1
1
  module Spree
2
2
  class Promotion < Spree.base_class
3
- include Spree::MultiStoreResource
3
+ has_prefix_id :promo # Spree-specific: promotion
4
+
5
+ include Spree::StoreScopedResource
4
6
  include Spree::Metafields
5
7
  include Spree::Metadata
6
8
  if defined?(Spree::Security::Promotions)
@@ -188,26 +190,14 @@ module Spree
188
190
  !!eligible_rules(promotable, options)
189
191
  end
190
192
 
191
- # We cache the rules to avoid multiple database queries
192
- # this is useful for orders with many line items
193
- #
194
- # @return [Array<Spree::PromotionRule>]
195
- def cached_rules
196
- Rails.cache.fetch("#{cache_key_with_version}/rules") do
197
- rules.to_a
198
- end
199
- rescue TypeError # when using null_store in test environment
200
- rules.to_a
201
- end
202
-
203
193
  # eligible_rules returns an array of promotion rules where eligible? is true for the promotable
204
194
  # if there are no such rules, an empty array is returned
205
195
  # if the rules make this promotable ineligible, then nil is returned (i.e. this promotable is not eligible)
206
196
  def eligible_rules(promotable, options = {})
207
197
  # Promotions without rules are eligible by default.
208
- return [] if cached_rules.none?
198
+ return [] if rules.none?
209
199
 
210
- specific_rules = cached_rules.select { |rule| rule.applicable?(promotable) }
200
+ specific_rules = rules.select { |rule| rule.applicable?(promotable) }
211
201
  return [] if specific_rules.none?
212
202
 
213
203
  rule_eligibility = Hash[specific_rules.map do |rule|
@@ -2,6 +2,8 @@
2
2
  # PromotionActions perform the necessary tasks when a promotion is activated by an event and determined to be eligible.
3
3
  module Spree
4
4
  class PromotionAction < Spree.base_class
5
+ has_prefix_id :pact
6
+
5
7
  acts_as_paranoid
6
8
 
7
9
  belongs_to :promotion, class_name: 'Spree::Promotion', touch: true
@@ -1,5 +1,7 @@
1
1
  module Spree
2
2
  class PromotionCategory < Spree.base_class
3
+ has_prefix_id :procat
4
+
3
5
  validates :name, presence: true
4
6
  has_many :promotions
5
7
  end
@@ -177,8 +177,8 @@ module Spree
177
177
 
178
178
  # Check for applied adjustments.
179
179
  discount = order.all_adjustments.promotion.eligible.detect do |p|
180
- p.cached_source.promotion.code.try(:downcase) == coupon_code ||
181
- Spree::CouponCode.unused.where(promotion_id: p.cached_source.promotion_id, code: coupon_code).exists?
180
+ p.source.promotion.code.try(:downcase) == coupon_code ||
181
+ Spree::CouponCode.unused.where(promotion_id: p.source.promotion_id, code: coupon_code).exists?
182
182
  end
183
183
 
184
184
  # Check for applied line items.
@@ -209,7 +209,7 @@ module Spree
209
209
  end
210
210
 
211
211
  def handle_coupon_code(discount, coupon_code)
212
- Spree::CouponCode.unused.find_by(promotion_id: discount.cached_source.promotion_id, code: coupon_code)&.apply_order!(order)
212
+ Spree::CouponCode.unused.find_by(promotion_id: discount.source.promotion_id, code: coupon_code)&.apply_order!(order)
213
213
  end
214
214
 
215
215
  def load_gift_card_code
@@ -1,6 +1,8 @@
1
1
  # Base class for all promotion rules
2
2
  module Spree
3
3
  class PromotionRule < Spree.base_class
4
+ has_prefix_id :prorule
5
+
4
6
  belongs_to :promotion, class_name: 'Spree::Promotion', inverse_of: :promotion_rules, touch: true
5
7
 
6
8
  delegate :stores, to: :promotion
@@ -1,9 +1,8 @@
1
1
  module Spree
2
2
  class Prototype < Spree.base_class
3
- include Spree::Metadata
3
+ has_prefix_id :proto
4
4
 
5
- has_many :property_prototypes, class_name: 'Spree::PropertyPrototype'
6
- has_many :properties, through: :property_prototypes, class_name: 'Spree::Property'
5
+ include Spree::Metadata
7
6
 
8
7
  has_many :option_type_prototypes, class_name: 'Spree::OptionTypePrototype'
9
8
  has_many :option_types, through: :option_type_prototypes, class_name: 'Spree::OptionType'