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
|
@@ -65,7 +65,11 @@ module Spree
|
|
|
65
65
|
#
|
|
66
66
|
# @return [BigDecimal] The total amount of store credits applied to the order.
|
|
67
67
|
def total_applied_store_credit
|
|
68
|
-
payments.
|
|
68
|
+
if payments.loaded?
|
|
69
|
+
payments.find_all(&:store_credit?).find_all(&:valid?).sum(&:amount) || BigDecimal::ZERO
|
|
70
|
+
else
|
|
71
|
+
payments.store_credits.valid.sum(:amount)
|
|
72
|
+
end
|
|
69
73
|
end
|
|
70
74
|
|
|
71
75
|
# Returns true if the order is using store credit.
|
data/app/models/spree/order.rb
CHANGED
|
@@ -28,6 +28,8 @@ module Spree
|
|
|
28
28
|
include Spree::NumberIdentifier
|
|
29
29
|
include Spree::NumberAsParam
|
|
30
30
|
include Spree::SingleStoreResource
|
|
31
|
+
|
|
32
|
+
publishes_lifecycle_events
|
|
31
33
|
include Spree::MemoizedData
|
|
32
34
|
include Spree::Metafields
|
|
33
35
|
include Spree::Metadata
|
|
@@ -40,6 +42,7 @@ module Spree
|
|
|
40
42
|
end
|
|
41
43
|
|
|
42
44
|
has_secure_token :token, length: 35
|
|
45
|
+
has_rich_text :internal_note
|
|
43
46
|
|
|
44
47
|
MEMOIZED_METHODS = %w(tax_zone)
|
|
45
48
|
|
|
@@ -202,8 +205,8 @@ module Spree
|
|
|
202
205
|
joins(:refunds).group(:id).having("sum(#{Spree::Refund.table_name}.amount) = #{Spree::Order.table_name}.total")
|
|
203
206
|
}
|
|
204
207
|
scope :partially_refunded, lambda {
|
|
205
|
-
|
|
206
|
-
|
|
208
|
+
joins(:refunds).group(:id).having("sum(#{Spree::Refund.table_name}.amount) < #{Spree::Order.table_name}.total")
|
|
209
|
+
}
|
|
207
210
|
scope :with_deleted_bill_address, -> { joins(:bill_address).where.not(Address.table_name => { deleted_at: nil }) }
|
|
208
211
|
scope :with_deleted_ship_address, -> { joins(:ship_address).where.not(Address.table_name => { deleted_at: nil }) }
|
|
209
212
|
|
|
@@ -268,15 +271,26 @@ module Spree
|
|
|
268
271
|
completed_at.present?
|
|
269
272
|
end
|
|
270
273
|
|
|
274
|
+
# Checks if the order is fully refunded
|
|
275
|
+
# @return [Boolean]
|
|
271
276
|
def order_refunded?
|
|
272
|
-
|
|
273
|
-
|
|
277
|
+
return false if item_count.zero?
|
|
278
|
+
|
|
279
|
+
(payment_state.in?(%w[void failed]) && refunds_total.positive?) ||
|
|
280
|
+
refunds_total == total_minus_store_credits - additional_tax_total.abs
|
|
274
281
|
end
|
|
275
282
|
|
|
283
|
+
def refunds_total
|
|
284
|
+
refunds.loaded? ? refunds.sum(&:amount) : refunds.sum(:amount)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# Checks if the order is partially refunded
|
|
288
|
+
# @return [Boolean]
|
|
276
289
|
def partially_refunded?
|
|
277
|
-
return false if
|
|
290
|
+
return false if item_count.zero?
|
|
291
|
+
return false if payment_state.in?(%w[void failed]) || refunds.empty?
|
|
278
292
|
|
|
279
|
-
|
|
293
|
+
refunds_total < total_minus_store_credits - additional_tax_total.abs
|
|
280
294
|
end
|
|
281
295
|
|
|
282
296
|
# Indicates whether or not the user is allowed to proceed to checkout.
|
|
@@ -391,6 +405,9 @@ module Spree
|
|
|
391
405
|
ActiveRecord::Base.connected_to(role: :writing) do
|
|
392
406
|
self.class.unscoped.where(id: self).update_all(changes)
|
|
393
407
|
end
|
|
408
|
+
|
|
409
|
+
# Manually publish update event since update_all bypasses callbacks
|
|
410
|
+
publish_event('order.updated') if changes.present?
|
|
394
411
|
end
|
|
395
412
|
|
|
396
413
|
def disassociate_user!
|
|
@@ -520,12 +537,11 @@ module Spree
|
|
|
520
537
|
|
|
521
538
|
touch :completed_at
|
|
522
539
|
|
|
523
|
-
deliver_order_confirmation_email unless confirmation_delivered?
|
|
524
|
-
deliver_store_owner_order_notification_email if deliver_store_owner_order_notification_email?
|
|
525
|
-
|
|
526
540
|
send_order_placed_webhook
|
|
527
541
|
|
|
528
542
|
consider_risk
|
|
543
|
+
|
|
544
|
+
publish_order_completed_event
|
|
529
545
|
end
|
|
530
546
|
|
|
531
547
|
def fulfill!
|
|
@@ -540,10 +556,7 @@ module Spree
|
|
|
540
556
|
end
|
|
541
557
|
|
|
542
558
|
def available_payment_methods(store = nil)
|
|
543
|
-
Spree::Deprecation.warn('`Order#available_payment_methods` is deprecated and will be removed in Spree
|
|
544
|
-
if store.present?
|
|
545
|
-
Spree::Deprecation.warn('The `store` parameter is deprecated and will be removed in Spree 5. Order is already associated with Store')
|
|
546
|
-
end
|
|
559
|
+
Spree::Deprecation.warn('`Order#available_payment_methods` is deprecated and will be removed in Spree 5.5. Use `collect_frontend_payment_methods` instead.')
|
|
547
560
|
|
|
548
561
|
@available_payment_methods ||= collect_payment_methods(store)
|
|
549
562
|
end
|
|
@@ -691,6 +704,10 @@ module Spree
|
|
|
691
704
|
if shipments.any? && !completed?
|
|
692
705
|
shipments.destroy_all
|
|
693
706
|
update_column(:shipment_total, 0)
|
|
707
|
+
|
|
708
|
+
# Manually publish update event since update_column bypasses callbacks
|
|
709
|
+
publish_event('order.updated')
|
|
710
|
+
|
|
694
711
|
restart_checkout_flow
|
|
695
712
|
end
|
|
696
713
|
end
|
|
@@ -700,6 +717,10 @@ module Spree
|
|
|
700
717
|
state: 'cart',
|
|
701
718
|
updated_at: Time.current
|
|
702
719
|
)
|
|
720
|
+
|
|
721
|
+
# Manually publish update event since update_columns bypasses callbacks
|
|
722
|
+
publish_event('order.updated')
|
|
723
|
+
|
|
703
724
|
next! unless line_items.empty?
|
|
704
725
|
end
|
|
705
726
|
|
|
@@ -733,24 +754,28 @@ module Spree
|
|
|
733
754
|
|
|
734
755
|
def canceled_by(user, canceled_at = nil)
|
|
735
756
|
canceled_at ||= Time.current
|
|
757
|
+
changes = { canceler_id: user.id, canceled_at: canceled_at }
|
|
736
758
|
|
|
737
759
|
transaction do
|
|
738
|
-
update_columns(
|
|
739
|
-
canceler_id: user.id,
|
|
740
|
-
canceled_at: canceled_at
|
|
741
|
-
)
|
|
760
|
+
update_columns(changes)
|
|
742
761
|
cancel!
|
|
743
762
|
end
|
|
763
|
+
|
|
764
|
+
# Manually publish update event since update_columns bypasses callbacks
|
|
765
|
+
publish_event('order.canceled')
|
|
744
766
|
end
|
|
745
767
|
|
|
746
768
|
def approved_by(user)
|
|
769
|
+
approved_at = Time.current
|
|
770
|
+
changes = { approver_id: user.id, approved_at: approved_at }
|
|
771
|
+
|
|
747
772
|
transaction do
|
|
748
773
|
approve!
|
|
749
|
-
update_columns(
|
|
750
|
-
approver_id: user.id,
|
|
751
|
-
approved_at: Time.current
|
|
752
|
-
)
|
|
774
|
+
update_columns(changes)
|
|
753
775
|
end
|
|
776
|
+
|
|
777
|
+
# Manually publish update event since update_columns bypasses callbacks
|
|
778
|
+
publish_event('order.approved')
|
|
754
779
|
end
|
|
755
780
|
|
|
756
781
|
def approved?
|
|
@@ -776,10 +801,16 @@ module Spree
|
|
|
776
801
|
|
|
777
802
|
def considered_risky!
|
|
778
803
|
update_column(:considered_risky, true)
|
|
804
|
+
|
|
805
|
+
# Manually publish update event since update_column bypasses callbacks
|
|
806
|
+
publish_event('order.updated')
|
|
779
807
|
end
|
|
780
808
|
|
|
781
809
|
def approve!
|
|
782
810
|
update_column(:considered_risky, false)
|
|
811
|
+
|
|
812
|
+
# Manually publish update event since update_column bypasses callbacks
|
|
813
|
+
publish_event('order.approved')
|
|
783
814
|
end
|
|
784
815
|
|
|
785
816
|
def tax_total
|
|
@@ -817,14 +848,22 @@ module Spree
|
|
|
817
848
|
Spree::CouponCode.find_by(order: self, promotion: promotions).try(:code) || promotions.pluck(:code).compact.first
|
|
818
849
|
end
|
|
819
850
|
|
|
851
|
+
# Returns the valid promotions for the order
|
|
852
|
+
# @return [Array<Spree::OrderPromotion>]
|
|
820
853
|
def valid_promotions
|
|
821
|
-
order_promotions.where(promotion_id: valid_promotion_ids).uniq(&:promotion_id)
|
|
854
|
+
order_promotions.includes(:promotion).where(promotion_id: valid_promotion_ids).uniq(&:promotion_id)
|
|
822
855
|
end
|
|
823
856
|
|
|
857
|
+
# Returns the IDs of the valid promotions for the order
|
|
858
|
+
# @return [Array<Integer>]
|
|
824
859
|
def valid_promotion_ids
|
|
825
|
-
all_adjustments.eligible.nonzero.promotion.
|
|
860
|
+
all_adjustments.eligible.nonzero.promotion.promotion.eligible.nonzero.promotion.
|
|
861
|
+
joins("INNER JOIN #{Spree::PromotionAction.table_name} ON #{Spree::PromotionAction.table_name}.id = #{Spree::Adjustment.table_name}.source_id").
|
|
862
|
+
pluck("#{Spree::PromotionAction.table_name}.promotion_id").compact.uniq
|
|
826
863
|
end
|
|
827
864
|
|
|
865
|
+
# Returns the valid coupon promotions for the order
|
|
866
|
+
# @return [Array<Spree::Promotion>]
|
|
828
867
|
def valid_coupon_promotions
|
|
829
868
|
promotions.
|
|
830
869
|
where(id: valid_promotion_ids).
|
|
@@ -832,7 +871,7 @@ module Spree
|
|
|
832
871
|
end
|
|
833
872
|
|
|
834
873
|
# Returns item and whole order discount amount for Order
|
|
835
|
-
# without Shipment
|
|
874
|
+
# without Shipment discounts (eg. Free Shipping)
|
|
836
875
|
# @return [BigDecimal]
|
|
837
876
|
def cart_promo_total
|
|
838
877
|
all_adjustments.eligible.nonzero.promotion.
|
|
@@ -897,7 +936,7 @@ module Spree
|
|
|
897
936
|
errors.add(:base, Spree.t(:items_cannot_be_shipped))
|
|
898
937
|
end
|
|
899
938
|
|
|
900
|
-
|
|
939
|
+
false
|
|
901
940
|
end
|
|
902
941
|
end
|
|
903
942
|
|
|
@@ -917,12 +956,14 @@ module Spree
|
|
|
917
956
|
send_cancel_email
|
|
918
957
|
update_with_updater!
|
|
919
958
|
send_order_canceled_webhook
|
|
959
|
+
publish_order_canceled_event
|
|
920
960
|
end
|
|
921
961
|
|
|
922
962
|
def after_resume
|
|
923
963
|
shipments.each(&:resume!)
|
|
924
964
|
consider_risk
|
|
925
965
|
send_order_resumed_webhook
|
|
966
|
+
publish_order_resumed_event
|
|
926
967
|
end
|
|
927
968
|
|
|
928
969
|
def use_billing?
|
|
@@ -937,12 +978,8 @@ module Spree
|
|
|
937
978
|
self.currency ||= store&.default_currency
|
|
938
979
|
end
|
|
939
980
|
|
|
940
|
-
def collect_payment_methods
|
|
941
|
-
Spree::Deprecation.warn('`Order#collect_payment_methods` is deprecated and will be removed in Spree
|
|
942
|
-
if store.present?
|
|
943
|
-
Spree::Deprecation.warn('The `store` parameter is deprecated and will be removed in Spree 5. Order is already associated with Store')
|
|
944
|
-
end
|
|
945
|
-
store ||= self.store
|
|
981
|
+
def collect_payment_methods
|
|
982
|
+
Spree::Deprecation.warn('`Order#collect_payment_methods` is deprecated and will be removed in Spree 5.5. Use `collect_frontend_payment_methods` instead.')
|
|
946
983
|
|
|
947
984
|
store.payment_methods.available_on_front_end.select { |pm| pm.available_for_order?(self) }
|
|
948
985
|
end
|
|
@@ -960,5 +997,17 @@ module Spree
|
|
|
960
997
|
Spree.checkout_add_store_credit_service.call(order: self)
|
|
961
998
|
end
|
|
962
999
|
end
|
|
1000
|
+
|
|
1001
|
+
def publish_order_completed_event
|
|
1002
|
+
publish_event('order.completed')
|
|
1003
|
+
end
|
|
1004
|
+
|
|
1005
|
+
def publish_order_canceled_event
|
|
1006
|
+
publish_event('order.canceled')
|
|
1007
|
+
end
|
|
1008
|
+
|
|
1009
|
+
def publish_order_resumed_event
|
|
1010
|
+
publish_event('order.resumed')
|
|
1011
|
+
end
|
|
963
1012
|
end
|
|
964
1013
|
end
|
|
@@ -79,15 +79,34 @@ module Spree
|
|
|
79
79
|
|
|
80
80
|
def update_adjustment_total
|
|
81
81
|
recalculate_adjustments
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
|
|
83
|
+
# Fetch all line item totals in a single query
|
|
84
|
+
# Use reorder(nil) to remove default ordering which conflicts with aggregates in PostgreSQL
|
|
85
|
+
line_item_totals = line_items.reorder(nil).pick(
|
|
86
|
+
Arel.sql('COALESCE(SUM(adjustment_total), 0)'),
|
|
87
|
+
Arel.sql('COALESCE(SUM(included_tax_total), 0)'),
|
|
88
|
+
Arel.sql('COALESCE(SUM(additional_tax_total), 0)'),
|
|
89
|
+
Arel.sql('COALESCE(SUM(promo_total), 0)')
|
|
90
|
+
) || [0, 0, 0, 0]
|
|
91
|
+
|
|
92
|
+
# Fetch all shipment totals in a single query
|
|
93
|
+
shipment_totals = shipments.reorder(nil).pick(
|
|
94
|
+
Arel.sql('COALESCE(SUM(adjustment_total), 0)'),
|
|
95
|
+
Arel.sql('COALESCE(SUM(included_tax_total), 0)'),
|
|
96
|
+
Arel.sql('COALESCE(SUM(additional_tax_total), 0)'),
|
|
97
|
+
Arel.sql('COALESCE(SUM(promo_total), 0)')
|
|
98
|
+
) || [0, 0, 0, 0]
|
|
99
|
+
|
|
100
|
+
# Fetch order-level adjustment totals in a single query
|
|
101
|
+
order_adjustment_totals = adjustments.eligible.reorder(nil).pick(
|
|
102
|
+
Arel.sql('COALESCE(SUM(amount), 0)'),
|
|
103
|
+
Arel.sql("COALESCE(SUM(CASE WHEN source_type = 'Spree::PromotionAction' THEN amount ELSE 0 END), 0)")
|
|
104
|
+
) || [0, 0]
|
|
105
|
+
|
|
106
|
+
order.adjustment_total = line_item_totals[0] + shipment_totals[0] + order_adjustment_totals[0]
|
|
107
|
+
order.included_tax_total = line_item_totals[1] + shipment_totals[1]
|
|
108
|
+
order.additional_tax_total = line_item_totals[2] + shipment_totals[2]
|
|
109
|
+
order.promo_total = line_item_totals[3] + shipment_totals[3] + order_adjustment_totals[1]
|
|
91
110
|
|
|
92
111
|
update_order_total
|
|
93
112
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spree
|
|
4
|
+
class Payment < Spree.base_class
|
|
5
|
+
# Publishes custom payment events beyond basic lifecycle events.
|
|
6
|
+
#
|
|
7
|
+
# Events:
|
|
8
|
+
# - payment.paid: Payment was completed
|
|
9
|
+
# - order.paid: Order is fully paid (no outstanding balance)
|
|
10
|
+
#
|
|
11
|
+
module CustomEvents
|
|
12
|
+
extend ActiveSupport::Concern
|
|
13
|
+
|
|
14
|
+
included do
|
|
15
|
+
after_commit :publish_payment_paid_event, on: :update, if: :should_publish_paid_event?
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def should_publish_paid_event?
|
|
21
|
+
return false unless Spree::Events.enabled?
|
|
22
|
+
return false unless state_previously_changed?
|
|
23
|
+
|
|
24
|
+
state_previous_change&.last == 'completed'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def publish_payment_paid_event
|
|
28
|
+
publish_event('payment.paid')
|
|
29
|
+
publish_order_paid_event if order.paid?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def publish_order_paid_event
|
|
33
|
+
order.publish_event('order.paid')
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/app/models/spree/payment.rb
CHANGED
|
@@ -15,6 +15,9 @@ module Spree
|
|
|
15
15
|
|
|
16
16
|
include Spree::Payment::Processing
|
|
17
17
|
include Spree::Payment::Webhooks
|
|
18
|
+
include Spree::Payment::CustomEvents
|
|
19
|
+
|
|
20
|
+
publishes_lifecycle_events
|
|
18
21
|
|
|
19
22
|
NON_RISKY_AVS_CODES = ['B', 'D', 'H', 'J', 'M', 'Q', 'T', 'V', 'X', 'Y'].freeze
|
|
20
23
|
RISKY_AVS_CODES = ['A', 'C', 'E', 'F', 'G', 'I', 'K', 'L', 'N', 'O', 'P', 'R', 'S', 'U', 'W', 'Z'].freeze
|
|
@@ -114,11 +117,11 @@ module Spree
|
|
|
114
117
|
event :complete do
|
|
115
118
|
transition from: [:processing, :pending, :checkout], to: :completed
|
|
116
119
|
end
|
|
117
|
-
after_transition to: :completed, do: [:after_completed, :send_payment_completed_webhook]
|
|
120
|
+
after_transition to: :completed, do: [:after_completed, :send_payment_completed_webhook, :publish_payment_completed_event]
|
|
118
121
|
event :void do
|
|
119
122
|
transition from: [:pending, :processing, :completed, :checkout], to: :void
|
|
120
123
|
end
|
|
121
|
-
after_transition to: :void, do: [:after_void, :send_payment_voided_webhook]
|
|
124
|
+
after_transition to: :void, do: [:after_void, :send_payment_voided_webhook, :publish_payment_voided_event]
|
|
122
125
|
# when the card brand isn't supported
|
|
123
126
|
event :invalidate do
|
|
124
127
|
transition from: [:checkout], to: :invalid
|
|
@@ -286,11 +289,17 @@ module Spree
|
|
|
286
289
|
end
|
|
287
290
|
|
|
288
291
|
def after_void
|
|
289
|
-
# Implement your logic here
|
|
290
292
|
end
|
|
291
293
|
|
|
292
294
|
def after_completed
|
|
293
|
-
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def publish_payment_completed_event
|
|
298
|
+
publish_event('payment.completed')
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def publish_payment_voided_event
|
|
302
|
+
publish_event('payment.voided')
|
|
294
303
|
end
|
|
295
304
|
|
|
296
305
|
def has_invalid_state?
|
|
@@ -18,7 +18,7 @@ module Spree
|
|
|
18
18
|
after_initialize :set_name, if: :new_record?
|
|
19
19
|
|
|
20
20
|
validates :name, presence: true
|
|
21
|
-
|
|
21
|
+
normalizes :name, with: ->(value) { value&.to_s&.squish&.presence }
|
|
22
22
|
|
|
23
23
|
has_many :store_payment_methods, class_name: 'Spree::StorePaymentMethod'
|
|
24
24
|
has_many :stores, class_name: 'Spree::Store', through: :store_payment_methods
|
|
@@ -26,9 +26,9 @@ module Spree
|
|
|
26
26
|
|
|
27
27
|
# Content pages
|
|
28
28
|
can :read, Spree::Policy
|
|
29
|
-
can :read, Spree::Page
|
|
30
|
-
can :read, Spree::Post
|
|
31
|
-
can :read, Spree::PostCategory
|
|
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
32
|
|
|
33
33
|
# Order management for the user's own orders
|
|
34
34
|
can :create, Spree::Order
|
data/app/models/spree/policy.rb
CHANGED
|
@@ -2,7 +2,6 @@ module Spree
|
|
|
2
2
|
class Policy < Spree.base_class
|
|
3
3
|
extend FriendlyId
|
|
4
4
|
include Spree::TranslatableResource
|
|
5
|
-
include Spree::Linkable
|
|
6
5
|
|
|
7
6
|
UNIQUENESS_SCOPE = %i[owner_id owner_type].freeze
|
|
8
7
|
|
|
@@ -37,7 +36,7 @@ module Spree
|
|
|
37
36
|
#
|
|
38
37
|
# Scopes
|
|
39
38
|
#
|
|
40
|
-
scope :with_body,
|
|
39
|
+
scope :with_body, -> { joins(:rich_text_body).distinct }
|
|
41
40
|
scope :without_body, -> { where.missing(:rich_text_body) }
|
|
42
41
|
scope :with_matching_name, ->(name_to_match) do
|
|
43
42
|
value = name_to_match.to_s.strip.downcase
|
|
@@ -62,12 +61,6 @@ module Spree
|
|
|
62
61
|
store.policies.or(where.not(owner_type: 'Spree::Store'))
|
|
63
62
|
end
|
|
64
63
|
|
|
65
|
-
def page_builder_url
|
|
66
|
-
return unless Spree::Core::Engine.routes.url_helpers.respond_to?(:policy_path)
|
|
67
|
-
|
|
68
|
-
Spree::Core::Engine.routes.url_helpers.policy_path(self)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
64
|
def with_body?
|
|
72
65
|
body.present?
|
|
73
66
|
end
|
data/app/models/spree/post.rb
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class Post < Spree.base_class
|
|
3
3
|
include Spree::SingleStoreResource
|
|
4
|
-
include Spree::Linkable
|
|
5
4
|
include Spree::Metafields
|
|
6
5
|
extend FriendlyId
|
|
7
6
|
|
|
7
|
+
publishes_lifecycle_events
|
|
8
|
+
|
|
8
9
|
friendly_id :slug_candidates, use: %i[slugged scoped history], scope: %i[store_id deleted?]
|
|
9
10
|
acts_as_paranoid
|
|
10
11
|
acts_as_taggable_on :tags
|
|
@@ -76,12 +77,6 @@ module Spree
|
|
|
76
77
|
published_at.present?
|
|
77
78
|
end
|
|
78
79
|
|
|
79
|
-
def page_builder_url
|
|
80
|
-
return unless Spree::Core::Engine.routes.url_helpers.respond_to?(:post_path)
|
|
81
|
-
|
|
82
|
-
Spree::Core::Engine.routes.url_helpers.post_path(self)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
80
|
def publish(date = nil)
|
|
86
81
|
update(published_at: date || Time.current)
|
|
87
82
|
end
|
data/app/models/spree/price.rb
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class Price < Spree.base_class
|
|
3
3
|
include Spree::VatPriceCalculation
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
end
|
|
4
|
+
|
|
5
|
+
publishes_lifecycle_events
|
|
7
6
|
|
|
8
7
|
acts_as_paranoid
|
|
9
8
|
|
|
10
9
|
MAXIMUM_AMOUNT = BigDecimal('99_999_999.99')
|
|
11
10
|
|
|
12
11
|
belongs_to :variant, -> { with_deleted }, class_name: 'Spree::Variant', inverse_of: :prices, touch: true
|
|
12
|
+
belongs_to :price_list, class_name: 'Spree::PriceList', optional: true
|
|
13
13
|
|
|
14
14
|
before_validation :ensure_currency
|
|
15
15
|
before_save :remove_compare_at_amount_if_equals_amount
|
|
@@ -20,11 +20,11 @@ module Spree
|
|
|
20
20
|
less_than_or_equal_to: MAXIMUM_AMOUNT
|
|
21
21
|
}, if: -> { Spree::Config.allow_empty_price_amount }
|
|
22
22
|
|
|
23
|
-
# new behavior
|
|
23
|
+
# new behavior - prices on a price_list can have nil amounts (placeholder prices)
|
|
24
24
|
validates :amount, allow_nil: false, numericality: {
|
|
25
25
|
greater_than_or_equal_to: 0,
|
|
26
26
|
less_than_or_equal_to: MAXIMUM_AMOUNT
|
|
27
|
-
}, unless: -> { Spree::Config.allow_empty_price_amount }
|
|
27
|
+
}, unless: -> { Spree::Config.allow_empty_price_amount || price_list_id.present? }
|
|
28
28
|
|
|
29
29
|
validates :compare_at_amount, allow_nil: true, numericality: {
|
|
30
30
|
greater_than_or_equal_to: 0,
|
|
@@ -36,6 +36,8 @@ module Spree
|
|
|
36
36
|
scope :with_currency, ->(currency) { where(currency: currency) }
|
|
37
37
|
scope :non_zero, -> { where.not(amount: [nil, 0]) }
|
|
38
38
|
scope :discounted, -> { where('compare_at_amount > amount') }
|
|
39
|
+
scope :base_prices, -> { where(price_list_id: nil) }
|
|
40
|
+
scope :for_price_list, ->(price_list) { where(price_list_id: price_list) }
|
|
39
41
|
scope :for_products, ->(products, currency = nil) do
|
|
40
42
|
currency ||= Spree::Store.default.default_currency
|
|
41
43
|
|
|
@@ -59,7 +61,7 @@ module Spree
|
|
|
59
61
|
end
|
|
60
62
|
|
|
61
63
|
def amount=(amount)
|
|
62
|
-
self[:amount] = Spree::LocalizedNumber.parse(amount)
|
|
64
|
+
self[:amount] = amount.blank? ? nil : Spree::LocalizedNumber.parse(amount)
|
|
63
65
|
end
|
|
64
66
|
|
|
65
67
|
def compare_at_money
|