spree_core 5.2.6 → 5.3.0.rc1
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.
- checksums.yaml +4 -4
- data/app/helpers/spree/addresses_helper.rb +1 -23
- data/app/helpers/spree/base_helper.rb +25 -77
- data/app/helpers/spree/currency_helper.rb +2 -2
- data/app/helpers/spree/images_helper.rb +5 -0
- data/app/helpers/spree/mail_helper.rb +1 -1
- data/app/helpers/spree/products_helper.rb +1 -1
- data/app/jobs/spree/events/subscriber_job.rb +58 -0
- data/app/jobs/spree/products/refresh_metrics_job.rb +14 -0
- data/app/jobs/spree/products/touch_taxons_job.rb +0 -1
- data/app/jobs/spree/variants/touch_job.rb +9 -0
- data/app/models/concerns/spree/adjustment_source.rb +8 -0
- data/app/models/concerns/spree/parameterizable_name.rb +1 -1
- data/app/models/concerns/spree/product_scopes.rb +54 -8
- data/app/models/concerns/spree/publishable.rb +253 -0
- data/app/models/concerns/spree/unique_name.rb +1 -1
- data/app/models/concerns/spree/user_methods.rb +21 -1
- data/app/models/spree/ability.rb +3 -3
- data/app/models/spree/address.rb +0 -3
- data/app/models/spree/adjustable/promotion_accumulator.rb +1 -1
- data/app/models/spree/adjustment.rb +32 -6
- data/app/models/spree/asset.rb +6 -3
- data/app/models/spree/base.rb +3 -1
- data/app/models/spree/classification.rb +2 -2
- data/app/models/spree/credit_card.rb +0 -3
- data/app/models/spree/current.rb +24 -3
- data/app/models/spree/custom_domain.rb +1 -1
- data/app/models/spree/customer_group.rb +94 -0
- data/app/models/spree/customer_group_user.rb +16 -0
- data/app/models/spree/customer_return.rb +2 -3
- data/app/models/spree/digital.rb +2 -4
- data/app/models/spree/digital_link.rb +2 -3
- data/app/models/spree/event.rb +104 -0
- data/app/models/spree/export.rb +7 -1
- data/app/models/spree/gift_card.rb +13 -1
- data/app/models/spree/gift_card_batch.rb +3 -1
- data/app/models/spree/image.rb +20 -5
- data/app/models/spree/import.rb +17 -12
- data/app/models/spree/import_row.rb +13 -26
- data/app/models/spree/inventory_unit.rb +0 -3
- data/app/models/spree/invitation.rb +12 -6
- data/app/models/spree/line_item.rb +57 -4
- data/app/models/spree/newsletter_subscriber.rb +2 -0
- data/app/models/spree/option_type.rb +2 -5
- data/app/models/spree/option_value.rb +1 -4
- data/app/models/spree/order/checkout.rb +7 -2
- data/app/models/spree/order/emails.rb +3 -11
- data/app/models/spree/order/store_credit.rb +5 -1
- data/app/models/spree/order.rb +80 -31
- data/app/models/spree/order_updater.rb +28 -9
- data/app/models/spree/payment/custom_events.rb +37 -0
- data/app/models/spree/payment.rb +13 -4
- data/app/models/spree/payment_capture_event.rb +0 -4
- data/app/models/spree/payment_method.rb +1 -1
- data/app/models/spree/permission_sets/default_customer.rb +3 -3
- data/app/models/spree/policy.rb +1 -8
- data/app/models/spree/post.rb +2 -7
- data/app/models/spree/post_category.rb +2 -0
- data/app/models/spree/price.rb +8 -6
- data/app/models/spree/price_list.rb +263 -0
- data/app/models/spree/price_rule.rb +26 -0
- data/app/models/spree/price_rules/customer_group_rule.rb +21 -0
- data/app/models/spree/price_rules/user_rule.rb +19 -0
- data/app/models/spree/price_rules/volume_rule.rb +21 -0
- data/app/models/spree/price_rules/zone_rule.rb +19 -0
- data/app/models/spree/product.rb +117 -76
- data/app/models/spree/product_property.rb +2 -2
- data/app/models/spree/promotion/rules/customer_group.rb +22 -0
- data/app/models/spree/promotion/rules/user.rb +2 -2
- data/app/models/spree/promotion.rb +3 -4
- data/app/models/spree/promotion_handler/coupon.rb +3 -3
- data/app/models/spree/property.rb +3 -6
- data/app/models/spree/prototype.rb +0 -3
- data/app/models/spree/refund.rb +2 -3
- data/app/models/spree/reimbursement.rb +5 -3
- data/app/models/spree/report.rb +7 -1
- data/app/models/spree/reports/products_performance.rb +1 -1
- data/app/models/spree/reports/sales_total.rb +1 -1
- data/app/models/spree/return_authorization.rb +7 -3
- data/app/models/spree/return_item.rb +15 -4
- data/app/models/spree/shipment/custom_events.rb +47 -0
- data/app/models/spree/shipment.rb +12 -5
- data/app/models/spree/shipping_category.rb +0 -3
- data/app/models/spree/shipping_method.rb +0 -3
- data/app/models/spree/stock/quantifier.rb +1 -1
- data/app/models/spree/stock_item.rb +2 -0
- data/app/models/spree/stock_location.rb +0 -3
- data/app/models/spree/stock_movement/custom_events.rb +44 -0
- data/app/models/spree/stock_movement.rb +3 -0
- data/app/models/spree/stock_transfer.rb +2 -3
- data/app/models/spree/store.rb +64 -92
- data/app/models/spree/store_credit.rb +3 -4
- data/app/models/spree/store_product.rb +14 -0
- data/app/models/spree/subscriber.rb +186 -0
- data/app/models/spree/tax_category.rb +0 -4
- data/app/models/spree/tax_rate.rb +0 -3
- data/app/models/spree/taxon.rb +3 -36
- data/app/models/spree/taxonomy.rb +0 -3
- data/app/models/spree/variant.rb +114 -21
- data/app/models/spree/webhook_delivery.rb +60 -0
- data/app/models/spree/webhook_endpoint.rb +53 -0
- data/app/models/spree/wished_item.rb +2 -4
- data/app/models/spree/wishlist.rb +2 -3
- data/app/models/spree/zone.rb +0 -9
- data/app/paginators/spree/shared/paginate.rb +4 -0
- data/app/serializers/spree/events/asset_serializer.rb +22 -0
- data/app/serializers/spree/events/base_serializer.rb +61 -0
- data/app/serializers/spree/events/customer_return_serializer.rb +20 -0
- data/app/serializers/spree/events/digital_link_serializer.rb +20 -0
- data/app/serializers/spree/events/digital_serializer.rb +18 -0
- data/app/serializers/spree/events/export_serializer.rb +22 -0
- data/app/serializers/spree/events/gift_card_batch_serializer.rb +24 -0
- data/app/serializers/spree/events/gift_card_serializer.rb +29 -0
- data/app/serializers/spree/events/image_serializer.rb +9 -0
- data/app/serializers/spree/events/import_row_serializer.rb +23 -0
- data/app/serializers/spree/events/import_serializer.rb +24 -0
- data/app/serializers/spree/events/invitation_serializer.rb +28 -0
- data/app/serializers/spree/events/line_item_serializer.rb +31 -0
- data/app/serializers/spree/events/newsletter_subscriber_serializer.rb +21 -0
- data/app/serializers/spree/events/order_serializer.rb +39 -0
- data/app/serializers/spree/events/payment_serializer.rb +24 -0
- data/app/serializers/spree/events/post_category_serializer.rb +20 -0
- data/app/serializers/spree/events/post_serializer.rb +26 -0
- data/app/serializers/spree/events/price_serializer.rb +22 -0
- data/app/serializers/spree/events/product_serializer.rb +24 -0
- data/app/serializers/spree/events/promotion_serializer.rb +32 -0
- data/app/serializers/spree/events/refund_serializer.rb +23 -0
- data/app/serializers/spree/events/reimbursement_serializer.rb +22 -0
- data/app/serializers/spree/events/report_serializer.rb +23 -0
- data/app/serializers/spree/events/return_authorization_serializer.rb +22 -0
- data/app/serializers/spree/events/return_item_serializer.rb +27 -0
- data/app/serializers/spree/events/shipment_serializer.rb +24 -0
- data/app/serializers/spree/events/stock_item_serializer.rb +22 -0
- data/app/serializers/spree/events/stock_movement_serializer.rb +22 -0
- data/app/serializers/spree/events/stock_transfer_serializer.rb +22 -0
- data/app/serializers/spree/events/store_credit_serializer.rb +30 -0
- data/app/serializers/spree/events/user_serializer.rb +18 -0
- data/app/serializers/spree/events/variant_serializer.rb +34 -0
- data/app/serializers/spree/events/wished_item_serializer.rb +20 -0
- data/app/serializers/spree/events/wishlist_serializer.rb +22 -0
- data/app/services/spree/addresses/update.rb +1 -1
- data/app/services/spree/cart/add_item.rb +1 -1
- data/app/services/spree/coupon_codes/coupon_codes_handler.rb +2 -1
- data/app/services/spree/data_feeds/google/required_attributes.rb +4 -4
- data/app/services/spree/newsletter/verify.rb +5 -0
- data/app/services/spree/products/auto_match_taxons.rb +1 -1
- data/app/services/spree/seeds/all.rb +1 -1
- data/app/services/spree/taxons/add_products.rb +8 -4
- data/app/services/spree/taxons/regenerate_products.rb +8 -0
- data/app/services/spree/taxons/remove_products.rb +12 -7
- data/app/subscribers/spree/event_log_subscriber.rb +64 -0
- data/app/subscribers/spree/export_subscriber.rb +26 -0
- data/app/subscribers/spree/invitation_email_subscriber.rb +40 -0
- data/app/subscribers/spree/product_metrics_subscriber.rb +29 -0
- data/app/subscribers/spree/report_subscriber.rb +26 -0
- data/config/locales/en.yml +126 -0
- data/db/migrate/20251110120000_create_spree_price_lists.rb +22 -0
- data/db/migrate/20251110120001_create_spree_price_rules.rb +13 -0
- data/db/migrate/20251110120002_add_price_list_id_to_spree_prices.rb +6 -0
- data/db/migrate/20251110120003_add_price_list_id_to_spree_line_items.rb +5 -0
- data/db/migrate/20251201172118_fix_indexes_on_friendly_id_slugs.rb +8 -0
- data/db/migrate/20251214000001_create_spree_webhook_endpoints.rb +19 -0
- data/db/migrate/20251214000002_create_spree_webhook_deliveries.rb +23 -0
- data/db/migrate/20251222000000_add_performance_indexes_to_spree_adjustments.rb +25 -0
- data/db/migrate/20260112000000_fix_spree_prices_unique_indexes.rb +33 -0
- data/db/migrate/20260115120000_create_spree_customer_groups.rb +14 -0
- data/db/migrate/20260115120001_create_spree_customer_group_users.rb +14 -0
- data/db/migrate/20260117140831_remove_not_null_constraint_from_policy_name.rb +5 -0
- data/db/migrate/20260118120000_add_statistics_to_store_products.rb +11 -0
- data/db/migrate/20260119120000_add_counter_caches_to_spree_products.rb +9 -0
- data/db/migrate/20260119170000_add_counter_caches_to_spree_taxons.rb +9 -0
- data/db/migrate/20260120120000_add_image_count_to_spree_variants.rb +9 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +14 -2
- data/lib/spree/core/configuration.rb +1 -0
- data/lib/spree/core/controller_helpers/auth.rb +0 -15
- data/lib/spree/core/controller_helpers/currency.rb +13 -9
- data/lib/spree/core/controller_helpers/search.rb +1 -1
- data/lib/spree/core/controller_helpers/store.rb +5 -1
- data/lib/spree/core/engine.rb +61 -78
- data/lib/spree/core/importer/order.rb +1 -1
- data/lib/spree/core/importer/product.rb +1 -1
- data/lib/spree/core/preferences/preferable.rb +14 -1
- data/lib/spree/core/pricing/context.rb +63 -0
- data/lib/spree/core/pricing/resolver.rb +129 -0
- data/lib/spree/core/search/base.rb +1 -1
- data/lib/spree/core/token_generator.rb +1 -1
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +42 -47
- data/lib/spree/events/adapters/active_support_notifications.rb +112 -0
- data/lib/spree/events/adapters/base.rb +193 -0
- data/lib/spree/events/registry.rb +99 -0
- data/lib/spree/events.rb +240 -0
- data/lib/spree/permitted_attributes.rb +13 -2
- data/lib/spree/testing_support/common_rake.rb +68 -35
- data/lib/spree/testing_support/factories/customer_group_factory.rb +6 -0
- data/lib/spree/testing_support/factories/customer_group_user_factory.rb +6 -0
- data/lib/spree/testing_support/factories/price_factory.rb +4 -0
- data/lib/spree/testing_support/factories/price_list_factory.rb +34 -0
- data/lib/spree/testing_support/factories/price_rule_factory.rb +49 -0
- data/lib/spree/testing_support/factories/promotion_rule_factory.rb +12 -0
- data/lib/spree/testing_support/factories/stock_item_factory.rb +6 -4
- data/lib/spree/testing_support/factories/store_product_factory.rb +6 -0
- data/lib/spree/testing_support/factories/taxon_factory.rb +0 -1
- data/lib/spree/testing_support/factories/webhook_delivery_factory.rb +48 -0
- data/lib/spree/testing_support/factories/webhook_endpoint_factory.rb +22 -0
- data/lib/spree/testing_support/lifecycle_events.rb +38 -0
- data/lib/spree/testing_support/store.rb +4 -2
- data/lib/spree/webhooks.rb +22 -0
- data/lib/tasks/products.rake +40 -0
- data/lib/tasks/taxons.rake +19 -0
- data/lib/tasks/variants.rake +18 -0
- metadata +112 -114
- data/app/jobs/spree/themes/duplicate_components_job.rb +0 -59
- data/app/jobs/spree/themes/screenshot_job.rb +0 -81
- data/app/models/concerns/spree/has_page_links.rb +0 -53
- data/app/models/spree/page.rb +0 -188
- data/app/models/spree/page_block.rb +0 -73
- data/app/models/spree/page_blocks/buttons.rb +0 -29
- data/app/models/spree/page_blocks/heading.rb +0 -18
- data/app/models/spree/page_blocks/image.rb +0 -20
- data/app/models/spree/page_blocks/link.rb +0 -21
- data/app/models/spree/page_blocks/mega_nav.rb +0 -33
- data/app/models/spree/page_blocks/mega_nav_with_subcategories.rb +0 -32
- data/app/models/spree/page_blocks/metafields.rb +0 -18
- data/app/models/spree/page_blocks/nav.rb +0 -15
- data/app/models/spree/page_blocks/newsletter_form.rb +0 -18
- data/app/models/spree/page_blocks/products/brand.rb +0 -15
- data/app/models/spree/page_blocks/products/buy_buttons.rb +0 -24
- data/app/models/spree/page_blocks/products/description.rb +0 -18
- data/app/models/spree/page_blocks/products/price.rb +0 -18
- data/app/models/spree/page_blocks/products/quantity_selector.rb +0 -20
- data/app/models/spree/page_blocks/products/share.rb +0 -8
- data/app/models/spree/page_blocks/products/title.rb +0 -19
- data/app/models/spree/page_blocks/products/variant_picker.rb +0 -13
- data/app/models/spree/page_blocks/subheading.rb +0 -17
- data/app/models/spree/page_blocks/text.rb +0 -16
- data/app/models/spree/page_link.rb +0 -60
- data/app/models/spree/page_section.rb +0 -222
- data/app/models/spree/page_sections/announcement_bar.rb +0 -28
- data/app/models/spree/page_sections/breadcrumbs.rb +0 -12
- data/app/models/spree/page_sections/collection_banner.rb +0 -18
- data/app/models/spree/page_sections/custom_code.rb +0 -11
- data/app/models/spree/page_sections/featured_posts.rb +0 -45
- data/app/models/spree/page_sections/featured_product.rb +0 -50
- data/app/models/spree/page_sections/featured_taxon.rb +0 -90
- data/app/models/spree/page_sections/featured_taxons.rb +0 -45
- data/app/models/spree/page_sections/footer.rb +0 -101
- data/app/models/spree/page_sections/header.rb +0 -62
- data/app/models/spree/page_sections/image_banner.rb +0 -55
- data/app/models/spree/page_sections/image_with_text.rb +0 -65
- data/app/models/spree/page_sections/main_password_footer.rb +0 -18
- data/app/models/spree/page_sections/main_password_header.rb +0 -20
- data/app/models/spree/page_sections/newsletter.rb +0 -54
- data/app/models/spree/page_sections/page_title.rb +0 -19
- data/app/models/spree/page_sections/post_details.rb +0 -19
- data/app/models/spree/page_sections/post_grid.rb +0 -19
- data/app/models/spree/page_sections/product_details.rb +0 -53
- data/app/models/spree/page_sections/product_grid.rb +0 -13
- data/app/models/spree/page_sections/related_products.rb +0 -58
- data/app/models/spree/page_sections/rich_text.rb +0 -31
- data/app/models/spree/page_sections/taxon_banner.rb +0 -18
- data/app/models/spree/page_sections/taxon_grid.rb +0 -17
- data/app/models/spree/page_sections/video.rb +0 -107
- data/app/models/spree/pages/account.rb +0 -19
- data/app/models/spree/pages/cart.rb +0 -19
- data/app/models/spree/pages/checkout.rb +0 -15
- data/app/models/spree/pages/custom.rb +0 -38
- data/app/models/spree/pages/homepage.rb +0 -72
- data/app/models/spree/pages/login.rb +0 -19
- data/app/models/spree/pages/password.rb +0 -59
- data/app/models/spree/pages/post.rb +0 -27
- data/app/models/spree/pages/post_list.rb +0 -36
- data/app/models/spree/pages/product_details.rb +0 -30
- data/app/models/spree/pages/search_results.rb +0 -43
- data/app/models/spree/pages/shop_all.rb +0 -40
- data/app/models/spree/pages/taxon.rb +0 -29
- data/app/models/spree/pages/taxon_list.rb +0 -41
- data/app/models/spree/pages/wishlist.rb +0 -15
- data/app/models/spree/theme.rb +0 -233
- data/app/models/spree/themes/default.rb +0 -97
- data/app/services/spree/taxons/touch_featured_sections.rb +0 -21
- data/db/migrate/20250120094216_create_page_builder_models.rb +0 -78
- data/db/migrate/20250305121352_remove_page_builder_indices.rb +0 -11
- data/db/migrate/20250825175217_add_missing_page_builder_indexes.rb +0 -7
- data/db/migrate/20250913130044_add_page_links_counter_cache_to_spree_stores.rb +0 -10
- data/lib/generators/spree/dummy/templates/initializers/devise.rb +0 -3
- data/lib/generators/spree/install/install_generator.rb +0 -219
- data/lib/generators/spree/install/templates/config/initializers/spree.rb +0 -126
- data/lib/spree/core/webhooks.rb +0 -21
- data/lib/spree/testing_support/factories/page_block_factory.rb +0 -22
- data/lib/spree/testing_support/factories/page_factory.rb +0 -33
- data/lib/spree/testing_support/factories/page_link_factory.rb +0 -7
- data/lib/spree/testing_support/factories/page_section_factory.rb +0 -27
- data/lib/spree/testing_support/factories/theme_factory.rb +0 -14
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spree
|
|
4
|
+
# Concern for models that publish events.
|
|
5
|
+
#
|
|
6
|
+
# This concern is included in Spree::Base, so all Spree models
|
|
7
|
+
# can emit events. Event payloads are generated using dedicated
|
|
8
|
+
# serializers from the Spree::Events namespace.
|
|
9
|
+
#
|
|
10
|
+
# @example Disabling events for a specific model
|
|
11
|
+
# class Spree::LogEntry < Spree.base_class
|
|
12
|
+
# self.publish_events = false
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# @example Publishing custom events
|
|
16
|
+
# class Spree::Order < Spree.base_class
|
|
17
|
+
# def complete!
|
|
18
|
+
# # ... completion logic ...
|
|
19
|
+
# publish_event('order.completed')
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# @example Creating an event serializer (required for each model that publishes events)
|
|
24
|
+
# # app/serializers/spree/events/order_serializer.rb
|
|
25
|
+
# class Spree::Events::OrderSerializer < Spree::Events::BaseSerializer
|
|
26
|
+
# protected
|
|
27
|
+
#
|
|
28
|
+
# def attributes
|
|
29
|
+
# {
|
|
30
|
+
# id: resource.id,
|
|
31
|
+
# number: resource.number,
|
|
32
|
+
# state: resource.state.to_s,
|
|
33
|
+
# # ... other attributes
|
|
34
|
+
# }
|
|
35
|
+
# end
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
module Publishable
|
|
39
|
+
extend ActiveSupport::Concern
|
|
40
|
+
|
|
41
|
+
# Error raised when a model tries to publish an event but has no serializer defined
|
|
42
|
+
class MissingSerializerError < StandardError
|
|
43
|
+
def initialize(model_class)
|
|
44
|
+
serializer_name = "Spree::Events::#{model_class.name.demodulize}Serializer"
|
|
45
|
+
super(
|
|
46
|
+
"Missing event serializer for #{model_class.name}. " \
|
|
47
|
+
"Please create #{serializer_name} that inherits from Spree::Events::BaseSerializer. " \
|
|
48
|
+
"Example:\n\n" \
|
|
49
|
+
" class #{serializer_name} < Spree::Events::BaseSerializer\n" \
|
|
50
|
+
" protected\n\n" \
|
|
51
|
+
" def attributes\n" \
|
|
52
|
+
" {\n" \
|
|
53
|
+
" id: resource.id,\n" \
|
|
54
|
+
" # add other attributes here\n" \
|
|
55
|
+
" updated_at: timestamp(resource.updated_at)\n" \
|
|
56
|
+
" }\n" \
|
|
57
|
+
" end\n" \
|
|
58
|
+
" end"
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
included do
|
|
64
|
+
class_attribute :publish_events, default: true
|
|
65
|
+
class_attribute :lifecycle_events_enabled, default: false
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class_methods do
|
|
69
|
+
# Enable automatic lifecycle event publishing
|
|
70
|
+
#
|
|
71
|
+
# @param options [Hash] Options for lifecycle events
|
|
72
|
+
# @option options [Array<Symbol>] :only Limit to specific events (:create, :update, :delete)
|
|
73
|
+
# @option options [Array<Symbol>] :except Exclude specific events
|
|
74
|
+
# @return [void]
|
|
75
|
+
#
|
|
76
|
+
# @example
|
|
77
|
+
# publishes_lifecycle_events
|
|
78
|
+
# publishes_lifecycle_events only: [:create, :delete]
|
|
79
|
+
# publishes_lifecycle_events except: [:update]
|
|
80
|
+
#
|
|
81
|
+
def publishes_lifecycle_events(options = {})
|
|
82
|
+
# Guard against duplicate callback registration (important for code reload in development)
|
|
83
|
+
return if lifecycle_events_enabled
|
|
84
|
+
|
|
85
|
+
self.lifecycle_events_enabled = true
|
|
86
|
+
|
|
87
|
+
events = [:create, :update, :delete]
|
|
88
|
+
events &= Array(options[:only]) if options[:only]
|
|
89
|
+
events -= Array(options[:except]) if options[:except]
|
|
90
|
+
|
|
91
|
+
if events.include?(:create)
|
|
92
|
+
after_commit :publish_create_event, on: :create, if: :should_publish_events?
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
if events.include?(:update)
|
|
96
|
+
after_commit :publish_update_event, on: :update, if: :should_publish_events?
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
if events.include?(:delete)
|
|
100
|
+
before_destroy :capture_pre_destroy_payload, if: :should_publish_events?
|
|
101
|
+
after_commit :publish_delete_event, on: :destroy, if: :should_publish_events?
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Disable lifecycle events for this model
|
|
106
|
+
#
|
|
107
|
+
# @example
|
|
108
|
+
# class Spree::LogEntry < Spree.base_class
|
|
109
|
+
# skip_lifecycle_events
|
|
110
|
+
# end
|
|
111
|
+
#
|
|
112
|
+
def skip_lifecycle_events
|
|
113
|
+
self.publish_events = false
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Get the event name prefix for this model
|
|
117
|
+
#
|
|
118
|
+
# If a parent class has explicitly set an event_prefix, it will be inherited.
|
|
119
|
+
# Otherwise, uses model_name.element (e.g., 'order' for Spree::Order)
|
|
120
|
+
#
|
|
121
|
+
# @return [String] e.g., 'order' for Spree::Order
|
|
122
|
+
def event_prefix
|
|
123
|
+
# If this class has an explicitly set prefix, use it
|
|
124
|
+
return @event_prefix if defined?(@event_prefix) && @event_prefix.present?
|
|
125
|
+
|
|
126
|
+
# Check if a parent class has an explicitly set prefix
|
|
127
|
+
parent = superclass
|
|
128
|
+
while parent && parent.respond_to?(:event_prefix)
|
|
129
|
+
if parent.instance_variable_defined?(:@event_prefix) && parent.instance_variable_get(:@event_prefix).present?
|
|
130
|
+
return parent.instance_variable_get(:@event_prefix)
|
|
131
|
+
end
|
|
132
|
+
parent = parent.superclass
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Default to model_name.element
|
|
136
|
+
@event_prefix ||= model_name.element
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Set a custom event prefix
|
|
140
|
+
#
|
|
141
|
+
# @param prefix [String]
|
|
142
|
+
def event_prefix=(prefix)
|
|
143
|
+
@event_prefix = prefix
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Publish an event with this model's data
|
|
148
|
+
#
|
|
149
|
+
# @param event_name [String] The event name (e.g., 'order.complete')
|
|
150
|
+
# @param payload [Hash, nil] Custom payload (defaults to event_payload)
|
|
151
|
+
# @param metadata [Hash] Additional metadata
|
|
152
|
+
# @return [Spree::Event] The published event
|
|
153
|
+
#
|
|
154
|
+
# @example
|
|
155
|
+
# order.publish_event('order.completed')
|
|
156
|
+
# order.publish_event('order.completed', { custom: 'data' })
|
|
157
|
+
# order.publish_event('order.completed', metadata: { user_id: 1 })
|
|
158
|
+
#
|
|
159
|
+
def publish_event(event_name, payload = nil, metadata = {})
|
|
160
|
+
return unless Spree::Events.enabled?
|
|
161
|
+
|
|
162
|
+
@_current_event_name = event_name
|
|
163
|
+
payload ||= event_payload
|
|
164
|
+
Spree::Events.publish(event_name, payload, metadata)
|
|
165
|
+
ensure
|
|
166
|
+
@_current_event_name = nil
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Get the payload for events
|
|
170
|
+
#
|
|
171
|
+
# Uses dedicated event serializer (Spree::Events::ModelSerializer).
|
|
172
|
+
# Raises MissingSerializerError if no serializer is defined.
|
|
173
|
+
#
|
|
174
|
+
# @return [Hash]
|
|
175
|
+
# @raise [MissingSerializerError] if no serializer is defined for this model
|
|
176
|
+
def event_payload
|
|
177
|
+
serializer = event_serializer_class
|
|
178
|
+
|
|
179
|
+
raise MissingSerializerError, self.class unless serializer
|
|
180
|
+
|
|
181
|
+
serializer.serialize(self, event_context)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Find the event serializer class for this model
|
|
185
|
+
#
|
|
186
|
+
# Looks for Spree::Events::ModelNameSerializer (e.g., Spree::Events::OrderSerializer)
|
|
187
|
+
# Also walks up the class hierarchy to find a serializer for parent classes.
|
|
188
|
+
# This allows subclasses like Spree::Exports::Products to use ExportSerializer.
|
|
189
|
+
#
|
|
190
|
+
# @return [Class, nil] The serializer class or nil if not found
|
|
191
|
+
def event_serializer_class
|
|
192
|
+
return nil unless self.class.name
|
|
193
|
+
|
|
194
|
+
# Try this class and walk up the hierarchy
|
|
195
|
+
klass = self.class
|
|
196
|
+
while klass && klass != Object && klass != BasicObject
|
|
197
|
+
class_name = klass.name&.demodulize
|
|
198
|
+
# Skip looking for BaseSerializer - that's the parent class for all serializers
|
|
199
|
+
if class_name.present? && class_name != 'Base'
|
|
200
|
+
serializer = "Spree::Events::#{class_name}Serializer".safe_constantize
|
|
201
|
+
return serializer if serializer
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
klass = klass.superclass
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
nil
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Context passed to the event serializer
|
|
211
|
+
#
|
|
212
|
+
# @return [Hash]
|
|
213
|
+
def event_context
|
|
214
|
+
{
|
|
215
|
+
event_name: @_current_event_name,
|
|
216
|
+
store_id: Spree::Current.store&.id,
|
|
217
|
+
triggered_at: Time.current
|
|
218
|
+
}
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Get the event prefix for this instance
|
|
222
|
+
#
|
|
223
|
+
# @return [String]
|
|
224
|
+
def event_prefix
|
|
225
|
+
self.class.event_prefix
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
private
|
|
229
|
+
|
|
230
|
+
def should_publish_events?
|
|
231
|
+
self.class.publish_events && Spree::Events.enabled?
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def publish_create_event
|
|
235
|
+
publish_event("#{event_prefix}.created")
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def publish_update_event
|
|
239
|
+
publish_event("#{event_prefix}.updated")
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def publish_delete_event
|
|
243
|
+
# For delete, we need to capture the data before it's gone
|
|
244
|
+
# The after_commit runs after the record is deleted, so we use
|
|
245
|
+
# the previously captured payload
|
|
246
|
+
publish_event("#{event_prefix}.deleted", @_pre_destroy_payload || event_payload)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def capture_pre_destroy_payload
|
|
250
|
+
@_pre_destroy_payload = event_payload
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
@@ -3,7 +3,7 @@ module Spree
|
|
|
3
3
|
extend ActiveSupport::Concern
|
|
4
4
|
|
|
5
5
|
included do
|
|
6
|
-
|
|
6
|
+
normalizes :name, with: ->(value) { value&.to_s&.squish&.presence }
|
|
7
7
|
|
|
8
8
|
validates :name, presence: true,
|
|
9
9
|
uniqueness: { case_sensitive: false, allow_blank: true, scope: spree_base_uniqueness_scope }
|
|
@@ -9,7 +9,12 @@ module Spree
|
|
|
9
9
|
include Spree::AdminUserMethods
|
|
10
10
|
include Spree::RansackableAttributes
|
|
11
11
|
include Spree::MultiSearchable
|
|
12
|
+
include Spree::Publishable
|
|
13
|
+
|
|
12
14
|
included do
|
|
15
|
+
# Enable lifecycle events for user models
|
|
16
|
+
publishes_lifecycle_events
|
|
17
|
+
|
|
13
18
|
# we need to have this callback before any dependent: :destroy associations
|
|
14
19
|
# https://github.com/rails/rails/issues/3458
|
|
15
20
|
before_validation :clone_billing_address, if: :use_billing?
|
|
@@ -18,7 +23,7 @@ module Spree
|
|
|
18
23
|
attr_accessor :use_billing
|
|
19
24
|
|
|
20
25
|
has_person_name
|
|
21
|
-
|
|
26
|
+
normalizes :email, :first_name, :last_name, with: ->(value) { value&.to_s&.squish&.presence }
|
|
22
27
|
acts_as_taggable_on :tags
|
|
23
28
|
|
|
24
29
|
#
|
|
@@ -33,6 +38,8 @@ module Spree
|
|
|
33
38
|
has_many :wished_items, through: :wishlists, source: :wished_items
|
|
34
39
|
has_many :gateway_customers, class_name: 'Spree::GatewayCustomer', foreign_key: :user_id
|
|
35
40
|
has_many :gift_cards, class_name: 'Spree::GiftCard', foreign_key: :user_id, dependent: :destroy
|
|
41
|
+
has_many :customer_group_users, class_name: 'Spree::CustomerGroupUser', foreign_key: :user_id, as: :user, dependent: :destroy
|
|
42
|
+
has_many :customer_groups, through: :customer_group_users, class_name: 'Spree::CustomerGroup'
|
|
36
43
|
belongs_to :ship_address, class_name: 'Spree::Address', optional: true
|
|
37
44
|
belongs_to :bill_address, class_name: 'Spree::Address', optional: true
|
|
38
45
|
|
|
@@ -40,6 +47,7 @@ module Spree
|
|
|
40
47
|
# Attachments
|
|
41
48
|
#
|
|
42
49
|
has_one_attached :avatar, service: Spree.public_storage_service_name
|
|
50
|
+
has_rich_text :internal_note
|
|
43
51
|
|
|
44
52
|
#
|
|
45
53
|
# Attributes
|
|
@@ -157,6 +165,18 @@ module Spree
|
|
|
157
165
|
name&.full
|
|
158
166
|
end
|
|
159
167
|
|
|
168
|
+
def event_serializer_class
|
|
169
|
+
Spree::Events::UserSerializer
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def event_prefix
|
|
173
|
+
if self.class == Spree.admin_user_class && Spree.admin_user_class != Spree.user_class
|
|
174
|
+
'admin'
|
|
175
|
+
else
|
|
176
|
+
'user'
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
160
180
|
private
|
|
161
181
|
|
|
162
182
|
def check_completed_orders
|
data/app/models/spree/ability.rb
CHANGED
|
@@ -166,9 +166,9 @@ module Spree
|
|
|
166
166
|
end
|
|
167
167
|
can :accept, Spree::Invitation, invitee_id: [user.id, nil], invitee_type: user.class.name, status: 'pending'
|
|
168
168
|
can :read, ::Spree::Policy
|
|
169
|
-
can :read, ::Spree::Page
|
|
170
|
-
can :read, ::Spree::Post
|
|
171
|
-
can :read, ::Spree::PostCategory
|
|
169
|
+
can :read, ::Spree::Page if defined?(Spree::Page)
|
|
170
|
+
can :read, ::Spree::Post if defined?(Spree::Post)
|
|
171
|
+
can :read, ::Spree::PostCategory if defined?(Spree::PostCategory)
|
|
172
172
|
end
|
|
173
173
|
|
|
174
174
|
def protect_admin_role
|
data/app/models/spree/address.rb
CHANGED
|
@@ -25,7 +25,7 @@ module Spree
|
|
|
25
25
|
def add_adjustment(adjustment, opts = {})
|
|
26
26
|
return unless adjustment.promotion?
|
|
27
27
|
|
|
28
|
-
source = opts[:source] || adjustment.
|
|
28
|
+
source = opts[:source] || adjustment.cached_source
|
|
29
29
|
promotion = opts[:promotion] || source.promotion
|
|
30
30
|
|
|
31
31
|
add(adjustments, adjustment, adjustment.id)
|
|
@@ -96,19 +96,45 @@ module Spree
|
|
|
96
96
|
!included?
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
+
# Returns the source using Rails.cache to avoid repeated database lookups.
|
|
100
|
+
# Sources are cached by their type and ID combination.
|
|
101
|
+
# Cache is automatically invalidated when the source is saved (see AdjustmentSource concern).
|
|
102
|
+
#
|
|
103
|
+
# @return [Object, nil] The source object (TaxRate, PromotionAction, etc.)
|
|
104
|
+
def cached_source
|
|
105
|
+
return nil if source_type.blank? || source_id.blank?
|
|
106
|
+
|
|
107
|
+
Rails.cache.fetch(source_cache_key) { source }
|
|
108
|
+
rescue TypeError
|
|
109
|
+
# Handle objects that can't be serialized (e.g., mock objects in tests)
|
|
110
|
+
source
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Cache key for the source object
|
|
114
|
+
def source_cache_key
|
|
115
|
+
"spree/adjustment_source/#{source_type}/#{source_id}"
|
|
116
|
+
end
|
|
117
|
+
|
|
99
118
|
# Passing a target here would always be recommended as it would avoid
|
|
100
119
|
# hitting the database again and would ensure you're compute values over
|
|
101
120
|
# the specific object amount passed here.
|
|
102
121
|
def update!(target = adjustable)
|
|
103
|
-
|
|
122
|
+
src = cached_source
|
|
123
|
+
return amount if closed? || src.blank?
|
|
124
|
+
|
|
125
|
+
new_amount = src.compute_amount(target)
|
|
126
|
+
new_eligible = promotion? ? src.promotion.eligible?(target) : eligible
|
|
104
127
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
128
|
+
changed_attributes = {}
|
|
129
|
+
changed_attributes[:amount] = new_amount if new_amount != amount
|
|
130
|
+
changed_attributes[:eligible] = new_eligible if new_eligible != eligible
|
|
108
131
|
|
|
109
|
-
|
|
132
|
+
if changed_attributes.any?
|
|
133
|
+
changed_attributes[:updated_at] = Time.current
|
|
134
|
+
update_columns(changed_attributes)
|
|
135
|
+
end
|
|
110
136
|
|
|
111
|
-
|
|
137
|
+
new_amount
|
|
112
138
|
end
|
|
113
139
|
|
|
114
140
|
private
|
data/app/models/spree/asset.rb
CHANGED
|
@@ -3,9 +3,8 @@ module Spree
|
|
|
3
3
|
include Support::ActiveStorage
|
|
4
4
|
include Spree::Metafields
|
|
5
5
|
include Spree::Metadata
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
end
|
|
6
|
+
|
|
7
|
+
publishes_lifecycle_events
|
|
9
8
|
|
|
10
9
|
EXTERNAL_URL_METAFIELD_KEY = 'external.url'
|
|
11
10
|
|
|
@@ -63,5 +62,9 @@ module Spree
|
|
|
63
62
|
def skip_import?
|
|
64
63
|
false
|
|
65
64
|
end
|
|
65
|
+
|
|
66
|
+
def event_prefix
|
|
67
|
+
'asset'
|
|
68
|
+
end
|
|
66
69
|
end
|
|
67
70
|
end
|
data/app/models/spree/base.rb
CHANGED
|
@@ -3,6 +3,7 @@ class Spree::Base < ApplicationRecord
|
|
|
3
3
|
include Spree::RansackableAttributes
|
|
4
4
|
include Spree::TranslatableResourceScopes
|
|
5
5
|
include Spree::IntegrationsConcern
|
|
6
|
+
include Spree::Publishable
|
|
6
7
|
|
|
7
8
|
after_initialize do
|
|
8
9
|
if has_attribute?(:preferences) && !preferences.nil?
|
|
@@ -10,7 +11,8 @@ class Spree::Base < ApplicationRecord
|
|
|
10
11
|
end
|
|
11
12
|
end
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
# only for backwards compatibility with Kaminari
|
|
15
|
+
if defined?(Kaminari) && Kaminari.config.page_method_name != :page
|
|
14
16
|
def self.page(num)
|
|
15
17
|
send Kaminari.config.page_method_name, num
|
|
16
18
|
end
|
|
@@ -4,8 +4,8 @@ module Spree
|
|
|
4
4
|
acts_as_list scope: :taxon
|
|
5
5
|
|
|
6
6
|
with_options inverse_of: :classifications, touch: true do
|
|
7
|
-
belongs_to :product, class_name: 'Spree::Product'
|
|
8
|
-
belongs_to :taxon, class_name: 'Spree::Taxon'
|
|
7
|
+
belongs_to :product, class_name: 'Spree::Product', counter_cache: :classification_count
|
|
8
|
+
belongs_to :taxon, class_name: 'Spree::Taxon', counter_cache: :classification_count
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
validates :taxon, :product, presence: true
|
data/app/models/spree/current.rb
CHANGED
|
@@ -1,13 +1,34 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class Current < ::ActiveSupport::CurrentAttributes
|
|
3
|
-
attribute :store, :
|
|
3
|
+
attribute :store, :currency, :zone, :price_lists, :global_pricing_context
|
|
4
4
|
|
|
5
5
|
def store
|
|
6
6
|
super || Spree::Store.default
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def
|
|
10
|
-
super || store&.
|
|
9
|
+
def currency
|
|
10
|
+
super || store&.default_currency
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def zone
|
|
14
|
+
super || Spree::Zone.default_tax || store&.checkout_zone
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def price_lists
|
|
18
|
+
super || begin
|
|
19
|
+
context = global_pricing_context
|
|
20
|
+
self.price_lists = Spree::PriceList.for_context(context)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def global_pricing_context
|
|
25
|
+
super || begin
|
|
26
|
+
self.global_pricing_context = Spree::Pricing::Context.new(
|
|
27
|
+
currency: currency,
|
|
28
|
+
store: store,
|
|
29
|
+
zone: zone
|
|
30
|
+
)
|
|
31
|
+
end
|
|
11
32
|
end
|
|
12
33
|
end
|
|
13
34
|
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
class CustomerGroup < Spree.base_class
|
|
3
|
+
acts_as_paranoid
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
# Associations
|
|
7
|
+
#
|
|
8
|
+
belongs_to :store, class_name: 'Spree::Store', inverse_of: :customer_groups
|
|
9
|
+
has_many :customer_group_users, class_name: 'Spree::CustomerGroupUser', dependent: :destroy
|
|
10
|
+
has_many :users, through: :customer_group_users, source: :user, source_type: Spree.user_class.to_s
|
|
11
|
+
|
|
12
|
+
#
|
|
13
|
+
# Validations
|
|
14
|
+
#
|
|
15
|
+
validates :name, presence: true, uniqueness: { scope: [:store_id], conditions: -> { where(deleted_at: nil) } }
|
|
16
|
+
validates :store, presence: true
|
|
17
|
+
|
|
18
|
+
#
|
|
19
|
+
# Scopes
|
|
20
|
+
#
|
|
21
|
+
scope :for_store, ->(store) { where(store: store) }
|
|
22
|
+
|
|
23
|
+
#
|
|
24
|
+
# Instance Methods
|
|
25
|
+
#
|
|
26
|
+
def users_count
|
|
27
|
+
customer_group_users.count
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Bulk add customers to the group
|
|
31
|
+
# @param user_ids [Array] array of user IDs to add
|
|
32
|
+
# @return [Integer] number of customers added
|
|
33
|
+
def add_customers(user_ids)
|
|
34
|
+
return 0 if user_ids.blank?
|
|
35
|
+
|
|
36
|
+
user_ids = Array(user_ids).map(&:to_s).uniq
|
|
37
|
+
return 0 if user_ids.empty?
|
|
38
|
+
|
|
39
|
+
# Get existing user IDs to avoid duplicates
|
|
40
|
+
existing_user_ids = customer_group_users.where(user_id: user_ids).pluck(:user_id).map(&:to_s).to_set
|
|
41
|
+
|
|
42
|
+
now = Time.current
|
|
43
|
+
user_type = Spree.user_class.to_s
|
|
44
|
+
|
|
45
|
+
records_to_insert = user_ids.filter_map do |user_id|
|
|
46
|
+
next if existing_user_ids.include?(user_id)
|
|
47
|
+
|
|
48
|
+
{
|
|
49
|
+
customer_group_id: id,
|
|
50
|
+
user_id: user_id,
|
|
51
|
+
user_type: user_type,
|
|
52
|
+
created_at: now,
|
|
53
|
+
updated_at: now
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
return 0 if records_to_insert.empty?
|
|
58
|
+
|
|
59
|
+
Spree::CustomerGroupUser.upsert_all(records_to_insert, on_duplicate: :skip)
|
|
60
|
+
added_user_ids = records_to_insert.map { |r| r[:user_id] }
|
|
61
|
+
touch_users(added_user_ids)
|
|
62
|
+
touch
|
|
63
|
+
|
|
64
|
+
records_to_insert.size
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Bulk remove customers from the group
|
|
68
|
+
# @param user_ids [Array] array of user IDs to remove
|
|
69
|
+
# @return [Integer] number of customers removed
|
|
70
|
+
def remove_customers(user_ids)
|
|
71
|
+
return 0 if user_ids.blank?
|
|
72
|
+
|
|
73
|
+
user_ids = Array(user_ids).map(&:to_s).uniq
|
|
74
|
+
return 0 if user_ids.empty?
|
|
75
|
+
|
|
76
|
+
deleted_count = customer_group_users.where(user_id: user_ids).delete_all
|
|
77
|
+
|
|
78
|
+
if deleted_count > 0
|
|
79
|
+
touch_users(user_ids)
|
|
80
|
+
touch
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
deleted_count
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def touch_users(user_ids)
|
|
89
|
+
return if user_ids.blank?
|
|
90
|
+
|
|
91
|
+
Spree.user_class.where(id: user_ids).touch_all
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
class CustomerGroupUser < Spree.base_class
|
|
3
|
+
#
|
|
4
|
+
# Associations
|
|
5
|
+
#
|
|
6
|
+
belongs_to :customer_group, class_name: 'Spree::CustomerGroup'
|
|
7
|
+
belongs_to :user, polymorphic: true
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Validations
|
|
11
|
+
#
|
|
12
|
+
validates :customer_group, presence: true
|
|
13
|
+
validates :user, presence: true
|
|
14
|
+
validates :customer_group_id, uniqueness: { scope: [:user_id, :user_type] }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -4,9 +4,8 @@ module Spree
|
|
|
4
4
|
include Spree::NumberIdentifier
|
|
5
5
|
include Spree::Metafields
|
|
6
6
|
include Spree::Metadata
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
end
|
|
7
|
+
|
|
8
|
+
publishes_lifecycle_events
|
|
10
9
|
|
|
11
10
|
belongs_to :stock_location
|
|
12
11
|
belongs_to :store, class_name: 'Spree::Store', inverse_of: :customer_returns
|
data/app/models/spree/digital.rb
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class Digital < Spree.base_class
|
|
3
|
+
publishes_lifecycle_events
|
|
4
|
+
|
|
3
5
|
belongs_to :variant
|
|
4
6
|
has_many :digital_links, dependent: :destroy
|
|
5
7
|
|
|
6
|
-
if defined?(Spree::Webhooks::HasWebhooks)
|
|
7
|
-
include Spree::Webhooks::HasWebhooks
|
|
8
|
-
end
|
|
9
|
-
|
|
10
8
|
has_one_attached :attachment, service: Spree.private_storage_service_name
|
|
11
9
|
|
|
12
10
|
validates :attachment, attached: true
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class DigitalLink < Spree.base_class
|
|
3
|
+
publishes_lifecycle_events
|
|
4
|
+
|
|
3
5
|
if Rails::VERSION::STRING >= '7.1.0'
|
|
4
6
|
has_secure_token on: :save
|
|
5
7
|
else
|
|
6
8
|
has_secure_token
|
|
7
9
|
end
|
|
8
10
|
|
|
9
|
-
if defined?(Spree::Webhooks::HasWebhooks)
|
|
10
|
-
include Spree::Webhooks::HasWebhooks
|
|
11
|
-
end
|
|
12
11
|
if defined?(Spree::Security::DigitalLinks)
|
|
13
12
|
include Spree::Security::DigitalLinks
|
|
14
13
|
end
|