spree_core 6.0.0.beta4 → 6.0.0.rc2
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/README.md +5 -5
- data/app/helpers/spree/images_helper.rb +0 -57
- data/app/jobs/spree/base_job.rb +21 -0
- data/app/jobs/spree/carts/reap_expired_job.rb +2 -2
- data/app/jobs/spree/collections/regenerate_time_based_job.rb +6 -3
- data/app/jobs/spree/orders/finalize_stale_drafts_job.rb +8 -5
- data/app/jobs/spree/payments/cancel_unused_sessions_job.rb +61 -0
- data/app/jobs/spree/search_provider/index_job.rb +4 -0
- data/app/jobs/spree/seller_payouts/sweep_seller_job.rb +2 -0
- data/app/jobs/spree/uploads/purge_unattached_job.rb +49 -0
- data/app/mailers/spree/admin_user_mailer.rb +4 -19
- data/app/mailers/spree/base_mailer.rb +97 -13
- data/app/mailers/spree/email_template_mailer.rb +27 -0
- data/app/mailers/spree/export_mailer.rb +3 -4
- data/app/mailers/spree/import_mailer.rb +3 -4
- data/app/mailers/spree/invitation_mailer.rb +24 -7
- data/app/mailers/spree/seller_user_mailer.rb +4 -16
- data/app/mailers/spree/webhook_mailer.rb +2 -2
- data/app/models/concerns/spree/acted_by.rb +1 -1
- data/app/models/concerns/spree/admin_user_methods.rb +15 -1
- data/app/models/concerns/spree/api_typed.rb +91 -0
- data/app/models/concerns/spree/calculated_adjustments.rb +41 -13
- data/app/models/concerns/spree/calculator/currency_amounts.rb +1 -1
- data/app/models/concerns/spree/calculator/tiers.rb +63 -0
- data/app/models/concerns/spree/canonical_decimals.rb +61 -0
- data/app/models/concerns/spree/customer_methods.rb +23 -18
- data/app/models/concerns/spree/derived_number.rb +11 -13
- data/app/models/concerns/spree/email_template_identity.rb +52 -0
- data/app/models/concerns/spree/parameterizable_name.rb +2 -0
- data/app/models/concerns/spree/payment_session_transitions.rb +8 -2
- data/app/models/concerns/spree/post_sale/taxation.rb +54 -0
- data/app/models/concerns/spree/post_sale/taxed_line.rb +51 -0
- data/app/models/concerns/spree/preference_schema/json_schema.rb +139 -0
- data/app/models/concerns/spree/preference_schema.rb +62 -32
- data/app/models/concerns/spree/product_scopes.rb +16 -2
- data/app/models/concerns/spree/provider_listing.rb +41 -0
- data/app/models/concerns/spree/publishable.rb +82 -14
- data/app/models/concerns/spree/purchase/addresses.rb +23 -10
- data/app/models/concerns/spree/purchase/currency.rb +1 -1
- data/app/models/concerns/spree/purchase/deprecated_aliases.rb +87 -0
- data/app/models/concerns/spree/purchase/gift_cards.rb +10 -4
- data/app/models/concerns/spree/purchase/locale.rb +1 -1
- data/app/models/concerns/spree/purchase/payment_processing.rb +8 -4
- data/app/models/concerns/spree/purchase/purchase_order.rb +9 -4
- data/app/models/concerns/spree/purchase/store_credits.rb +36 -1
- data/app/models/concerns/spree/purchase/totals.rb +49 -8
- data/app/models/concerns/spree/ransackable_attributes.rb +46 -0
- data/app/models/concerns/spree/receivable.rb +1 -1
- data/app/models/concerns/spree/searchable.rb +0 -4
- data/app/models/concerns/spree/secret_preferences.rb +59 -0
- data/app/models/concerns/spree/signed_id_attachments.rb +54 -0
- data/app/models/concerns/spree/single_store_resource.rb +1 -1
- data/app/models/concerns/spree/stores/email_branding.rb +32 -0
- data/app/models/concerns/spree/stores/markets.rb +5 -2
- data/app/models/concerns/spree/type_labels.rb +38 -0
- data/app/models/concerns/spree/typed_adjustment_line.rb +5 -6
- data/app/models/concerns/spree/typed_associations.rb +12 -18
- data/app/models/concerns/spree/vat_price_calculation.rb +5 -6
- data/app/models/spree/address.rb +12 -2
- data/app/models/spree/adjusters/largest_remainder.rb +14 -1
- data/app/models/spree/adjusters/promotion.rb +4 -19
- data/app/models/spree/allowed_origin.rb +3 -1
- data/app/models/spree/api_key.rb +5 -6
- data/app/models/spree/authentication/strategies/oidc_strategy.rb +5 -5
- data/app/models/spree/base.rb +99 -22
- data/app/models/spree/calculator/flat_percent_item_total.rb +2 -4
- data/app/models/spree/calculator/flat_rate.rb +3 -5
- data/app/models/spree/calculator/flexi_rate.rb +4 -6
- data/app/models/spree/calculator/percent_on_line_item.rb +2 -2
- data/app/models/spree/calculator/price_sack.rb +5 -7
- data/app/models/spree/calculator/shipping/digital_delivery.rb +3 -5
- data/app/models/spree/calculator/shipping/flat_percent_item_total.rb +7 -7
- data/app/models/spree/calculator/shipping/flat_rate.rb +5 -7
- data/app/models/spree/calculator/shipping/flexi_rate.rb +4 -6
- data/app/models/spree/calculator/shipping/per_item.rb +3 -5
- data/app/models/spree/calculator/shipping/price_sack.rb +5 -7
- data/app/models/spree/calculator/tiered_flat_rate.rb +7 -24
- data/app/models/spree/calculator/tiered_percent.rb +7 -25
- data/app/models/spree/cart.rb +78 -18
- data/app/models/spree/catalog.rb +1 -0
- data/app/models/spree/catalog_price.rb +0 -7
- data/app/models/spree/catalog_price_tier.rb +0 -8
- data/app/models/spree/category.rb +3 -1
- data/app/models/spree/channel/gating.rb +3 -2
- data/app/models/spree/channel.rb +6 -4
- data/app/models/spree/claim.rb +22 -1
- data/app/models/spree/claim_line_item.rb +41 -6
- data/app/models/spree/collection.rb +2 -1
- data/app/models/spree/collection_rule.rb +5 -21
- data/app/models/spree/commission_line.rb +1 -1
- data/app/models/spree/commission_rate.rb +7 -4
- data/app/models/spree/commission_rate_value.rb +1 -1
- data/app/models/spree/commission_rule.rb +4 -11
- data/app/models/spree/commission_rules/category_rule.rb +2 -5
- data/app/models/spree/commission_rules/item_total_rule.rb +2 -2
- data/app/models/spree/commission_rules/product_rule.rb +1 -1
- data/app/models/spree/commission_rules/seller_rule.rb +2 -5
- data/app/models/spree/company.rb +1 -0
- data/app/models/spree/company_invitation.rb +1 -0
- data/app/models/spree/consent_record.rb +0 -1
- data/app/models/spree/credit_card.rb +1 -1
- data/app/models/spree/current.rb +23 -0
- data/app/models/spree/custom_field.rb +2 -2
- data/app/models/spree/custom_field_definition.rb +20 -35
- data/app/models/spree/custom_fields/boolean.rb +1 -1
- data/app/models/spree/custom_fields/json.rb +1 -1
- data/app/models/spree/customer_group.rb +1 -0
- data/app/models/spree/data_feed/google.rb +0 -2
- data/app/models/spree/data_request.rb +2 -1
- data/app/models/spree/delivery_method.rb +36 -14
- data/app/models/spree/delivery_method_rule.rb +4 -11
- data/app/models/spree/delivery_method_rules/channel_rule.rb +2 -5
- data/app/models/spree/delivery_method_rules/item_total_rule.rb +2 -2
- data/app/models/spree/delivery_profile.rb +1 -0
- data/app/models/spree/delivery_rate.rb +7 -8
- data/app/models/spree/delivery_rate_provider/base.rb +1 -0
- data/app/models/spree/delivery_zone.rb +1 -2
- data/app/models/spree/delivery_zone_member.rb +4 -4
- data/app/models/spree/digital_asset.rb +7 -0
- data/app/models/spree/digital_asset_provider/base.rb +2 -0
- data/app/models/spree/digital_link.rb +2 -5
- data/app/models/spree/discount.rb +1 -1
- data/app/models/spree/email_template.rb +25 -0
- data/app/models/spree/email_template_draft.rb +13 -0
- data/app/models/spree/email_template_revision.rb +17 -0
- data/app/models/spree/email_templates/entry.rb +118 -0
- data/app/models/spree/email_templates/sample_record.rb +16 -0
- data/app/models/spree/emails/branding.rb +80 -0
- data/app/models/spree/exchange.rb +16 -1
- data/app/models/spree/exchange_line_item.rb +121 -5
- data/app/models/spree/export.rb +0 -1
- data/app/models/spree/exports/products.rb +10 -1
- data/app/models/spree/exports/report.rb +3 -3
- data/app/models/spree/fee.rb +4 -2
- data/app/models/spree/file_upload.rb +155 -0
- data/app/models/spree/fulfillment.rb +66 -30
- data/app/models/spree/fulfillment_changer.rb +2 -2
- data/app/models/spree/fulfillment_group.rb +6 -1
- data/app/models/spree/fulfillment_item.rb +0 -4
- data/app/models/spree/fulfillment_provider/base.rb +1 -0
- data/app/models/spree/gateway/bogus.rb +6 -0
- data/app/models/spree/gateway/custom_payment_source_method.rb +5 -0
- data/app/models/spree/gateway.rb +6 -2
- data/app/models/spree/gift_card.rb +18 -8
- data/app/models/spree/gift_card_batch.rb +3 -5
- data/app/models/spree/import.rb +5 -7
- data/app/models/spree/import_mapping.rb +1 -2
- data/app/models/spree/import_row.rb +2 -2
- data/app/models/spree/import_schemas/products.rb +1 -0
- data/app/models/spree/integration.rb +9 -19
- data/app/models/spree/invitation.rb +5 -5
- data/app/models/spree/line_item.rb +15 -4
- data/app/models/spree/locale.rb +11 -8
- data/app/models/spree/market.rb +8 -2
- data/app/models/spree/media.rb +1 -9
- data/app/models/spree/newsletter_subscriber.rb +4 -0
- data/app/models/spree/option_type.rb +2 -1
- data/app/models/spree/option_value.rb +2 -1
- data/app/models/spree/order.rb +60 -142
- data/app/models/spree/order_group.rb +18 -4
- data/app/models/spree/order_inventory.rb +10 -5
- data/app/models/spree/order_promotion.rb +1 -1
- data/app/models/spree/order_routing/has_strategy_preference.rb +1 -1
- data/app/models/spree/order_routing/strategy/base.rb +4 -2
- data/app/models/spree/order_routing/strategy/rules.rb +1 -1
- data/app/models/spree/order_routing_rule.rb +6 -22
- data/app/models/spree/package_type.rb +2 -2
- data/app/models/spree/payment/gateway_options.rb +15 -53
- data/app/models/spree/payment/processing.rb +2 -4
- data/app/models/spree/payment.rb +21 -13
- data/app/models/spree/payment_method/check.rb +2 -0
- data/app/models/spree/payment_method/session_instrumentation.rb +1 -0
- data/app/models/spree/payment_method/store_credit.rb +15 -13
- data/app/models/spree/payment_method.rb +78 -6
- data/app/models/spree/payment_session.rb +5 -1
- data/app/models/spree/payment_setup_session.rb +1 -0
- data/app/models/spree/payout_provider/base.rb +3 -1
- data/app/models/spree/pickup_point_provider/base.rb +2 -0
- data/app/models/spree/policy.rb +1 -0
- data/app/models/spree/price.rb +17 -14
- data/app/models/spree/price_adjustment_tier.rb +4 -0
- data/app/models/spree/price_list.rb +14 -9
- data/app/models/spree/price_rules/channel_rule.rb +3 -6
- data/app/models/spree/price_rules/customer_group_rule.rb +3 -6
- data/app/models/spree/price_rules/market_rule.rb +2 -5
- data/app/models/spree/price_rules/user_rule.rb +1 -3
- data/app/models/spree/product/channels.rb +9 -2
- data/app/models/spree/product.rb +54 -30
- data/app/models/spree/product_submission.rb +0 -12
- data/app/models/spree/product_type.rb +1 -1
- data/app/models/spree/promotion/actions/create_line_items.rb +28 -18
- data/app/models/spree/promotion/rules/category.rb +1 -5
- data/app/models/spree/promotion/rules/channel.rb +2 -9
- data/app/models/spree/promotion/rules/country.rb +3 -8
- data/app/models/spree/promotion/rules/currency.rb +1 -5
- data/app/models/spree/promotion/rules/customer_group.rb +2 -9
- data/app/models/spree/promotion/rules/first_order.rb +0 -4
- data/app/models/spree/promotion/rules/item_total.rb +6 -10
- data/app/models/spree/promotion/rules/market.rb +2 -9
- data/app/models/spree/promotion/rules/one_use_per_user.rb +0 -4
- data/app/models/spree/promotion/rules/option_value.rb +2 -6
- data/app/models/spree/promotion/rules/product.rb +1 -5
- data/app/models/spree/promotion/rules/user.rb +0 -4
- data/app/models/spree/promotion/rules/user_logged_in.rb +0 -4
- data/app/models/spree/promotion.rb +36 -6
- data/app/models/spree/promotion_action.rb +7 -14
- data/app/models/spree/promotion_action_line_item.rb +1 -1
- data/app/models/spree/promotion_handler/coupon.rb +59 -27
- data/app/models/spree/promotion_rule.rb +7 -14
- data/app/models/spree/purchase_order.rb +3 -0
- data/app/models/spree/quantity_rule.rb +1 -1
- data/app/models/spree/refund.rb +41 -18
- data/app/models/spree/return.rb +31 -2
- data/app/models/spree/return_line_item.rb +65 -14
- data/app/models/spree/role.rb +7 -7
- data/app/models/spree/saved_report.rb +2 -1
- data/app/models/spree/search_provider/base.rb +4 -0
- data/app/models/spree/seller.rb +10 -2
- data/app/models/spree/seller_payout.rb +8 -0
- data/app/models/spree/seller_requirement.rb +5 -12
- data/app/models/spree/seller_requirement_custom_field.rb +1 -2
- data/app/models/spree/seller_requirement_submission.rb +3 -2
- data/app/models/spree/seller_requirements/accept_terms.rb +2 -3
- data/app/models/spree/seller_transfer.rb +6 -0
- data/app/models/spree/shipping_label.rb +2 -0
- data/app/models/spree/stock/availability_validator.rb +2 -2
- data/app/models/spree/stock/estimator.rb +1 -1
- data/app/models/spree/stock/inventory_unit_builder.rb +1 -1
- data/app/models/spree/stock/packer.rb +2 -2
- data/app/models/spree/stock/splitter/weight.rb +1 -1
- data/app/models/spree/stock_level/custom_events.rb +6 -0
- data/app/models/spree/stock_level.rb +3 -1
- data/app/models/spree/stock_location.rb +1 -0
- data/app/models/spree/stock_movement.rb +1 -1
- data/app/models/spree/stock_receipt_item.rb +1 -1
- data/app/models/spree/stock_reservation.rb +2 -2
- data/app/models/spree/stock_transfer.rb +6 -2
- data/app/models/spree/store.rb +70 -19
- data/app/models/spree/store_credit.rb +13 -13
- data/app/models/spree/store_credit_event.rb +5 -5
- data/app/models/spree/supplier.rb +1 -0
- data/app/models/spree/tax_category.rb +1 -0
- data/app/models/spree/tax_exemption_certificate.rb +3 -0
- data/app/models/spree/tax_identifier.rb +3 -1
- data/app/models/spree/tax_line.rb +53 -3
- data/app/models/spree/tax_provider/base.rb +71 -14
- data/app/models/spree/tax_provider/internal.rb +70 -41
- data/app/models/spree/tax_provider/recorded_share.rb +114 -0
- data/app/models/spree/tax_rate.rb +30 -8
- data/app/models/spree/taxon.rb +1 -1
- data/app/models/spree/taxonomy.rb +0 -1
- data/app/models/spree/update_status.rb +25 -0
- data/app/models/spree/variant.rb +10 -12
- data/app/models/spree/variant_media.rb +1 -1
- data/app/models/spree/webhook_delivery.rb +1 -0
- data/app/models/spree/webhook_endpoint.rb +46 -13
- data/app/models/spree/wishlist.rb +1 -6
- data/app/models/spree/wishlist_item/custom_events.rb +6 -0
- data/app/presenters/spree/csv/customer_presenter.rb +1 -1
- data/app/presenters/spree/csv/newsletter_subscriber_presenter.rb +1 -1
- data/app/presenters/spree/csv/order_line_item_presenter.rb +10 -6
- data/app/presenters/spree/csv/price_list_price_presenter.rb +3 -8
- data/app/presenters/spree/csv/product_variant_presenter.rb +59 -20
- data/app/presenters/spree/csv/purchase_order_item_presenter.rb +1 -3
- data/app/serializers/spree/emails/base_serializer.rb +14 -0
- data/app/serializers/spree/emails/export_serializer.rb +13 -0
- data/app/serializers/spree/emails/import_serializer.rb +19 -0
- data/app/serializers/spree/emails/invitation_serializer.rb +28 -0
- data/app/serializers/spree/emails/store_serializer.rb +31 -0
- data/app/serializers/spree/emails/user_serializer.rb +12 -0
- data/app/serializers/spree/emails/webhook_endpoint_serializer.rb +16 -0
- data/app/services/spree/carts/create.rb +8 -2
- data/app/services/spree/carts/destroy.rb +2 -2
- data/app/services/spree/carts/remove_out_of_stock_items.rb +2 -2
- data/app/services/spree/carts/split_by_seller.rb +1 -1
- data/app/services/spree/carts/update.rb +22 -8
- data/app/services/spree/catalogs/set_product_terms.rb +1 -1
- data/app/services/spree/categories/add_products.rb +13 -31
- data/app/services/spree/categories/remove_products.rb +12 -51
- data/app/services/spree/checkout/advance.rb +1 -4
- data/app/services/spree/collections/add_products.rb +10 -23
- data/app/services/spree/collections/remove_products.rb +7 -43
- data/app/services/spree/coupon_codes/bulk_generate.rb +8 -14
- data/app/services/spree/data_requests/create.rb +1 -1
- data/app/services/spree/deliveries/destroy.rb +2 -2
- data/app/services/spree/email_templates/check.rb +58 -0
- data/app/services/spree/email_templates/no_sample_record.rb +7 -0
- data/app/services/spree/email_templates/preview.rb +99 -0
- data/app/services/spree/emails/file_system.rb +23 -0
- data/app/services/spree/emails/filters.rb +84 -0
- data/app/services/spree/emails/liquid_context.rb +48 -0
- data/app/services/spree/emails/rendered_email.rb +14 -0
- data/app/services/spree/emails/renderer.rb +125 -0
- data/app/services/spree/emails/template.rb +51 -0
- data/app/services/spree/emails/template_data.rb +23 -0
- data/app/services/spree/emails/template_resolver.rb +109 -0
- data/app/services/spree/emails/text_converter.rb +72 -0
- data/app/services/spree/emails/translation_inliner.rb +134 -0
- data/app/services/spree/imports/row_processors/price_list_price.rb +10 -10
- data/app/services/spree/imports/row_processors/product_variant.rb +77 -34
- data/app/services/spree/imports/row_processors/purchase_order.rb +13 -13
- data/app/services/spree/locales.rb +43 -10
- data/app/services/spree/newsletter/subscribe.rb +8 -12
- data/app/services/spree/orders/build_fulfillments.rb +3 -2
- data/app/services/spree/orders/create.rb +5 -4
- data/app/services/spree/orders/discounts/create.rb +14 -11
- data/app/services/spree/orders/discounts/destroy.rb +1 -0
- data/app/services/spree/orders/discounts/update.rb +1 -0
- data/app/services/spree/orders/fees/create.rb +1 -0
- data/app/services/spree/orders/fees/destroy.rb +1 -0
- data/app/services/spree/orders/fees/update.rb +1 -0
- data/app/services/spree/orders/remove_line_item.rb +13 -3
- data/app/services/spree/orders/update.rb +10 -6
- data/app/services/spree/orders/update_item.rb +6 -3
- data/app/services/spree/orders/update_statuses.rb +3 -1
- data/app/services/spree/prices/bulk_upsert.rb +32 -25
- data/app/services/spree/product_memberships.rb +61 -0
- data/app/services/spree/returns/eligibility_validator.rb +1 -1
- data/app/services/spree/search_provider/custom_field_schema.rb +2 -2
- data/app/services/spree/seeds/commission_rates.rb +1 -1
- data/app/services/spree/seeds/digital_delivery.rb +1 -1
- data/app/services/spree/seeds/payment_methods.rb +2 -2
- data/app/services/spree/seeds/saved_reports.rb +3 -3
- data/app/services/spree/seeds/stores.rb +1 -1
- data/app/services/spree/sellers/requirements.rb +1 -2
- data/app/services/spree/shipping_labels/confirm_refund.rb +1 -1
- data/app/services/spree/shipping_labels/store_file.rb +3 -3
- data/app/services/spree/stock_levels/correct.rb +3 -3
- data/app/services/spree/stock_reservations/reserve.rb +2 -3
- data/app/services/spree/store_credits/apply.rb +15 -13
- data/app/services/spree/stores/provision_defaults.rb +23 -25
- data/app/services/spree/update_check.rb +160 -0
- data/app/services/spree/uploads/assign_stores.rb +92 -0
- data/app/subscribers/spree/seller_onboarding_subscriber.rb +1 -1
- data/app/validators/spree/attachment_content_type_validator.rb +19 -2
- data/app/validators/spree/locale_codes_validator.rb +22 -0
- data/app/views/layouts/spree/base_mailer.html.erb +2 -43
- data/app/views/layouts/spree/base_mailer.liquid +79 -0
- data/app/views/spree/admin_user_mailer/password_reset_email.liquid +14 -0
- data/app/views/spree/export_mailer/export_done.liquid +12 -0
- data/app/views/spree/import_mailer/import_done.liquid +15 -0
- data/app/views/spree/invitation_mailer/invitation_accepted.liquid +9 -0
- data/app/views/spree/invitation_mailer/invitation_email.liquid +13 -0
- data/app/views/spree/seller_user_mailer/password_reset_email.liquid +14 -0
- data/app/views/spree/shared/_mailer_button.html.erb +4 -5
- data/app/views/spree/shared/_mailer_hero.html.erb +6 -5
- data/app/views/spree/shared/_summary_row.liquid +8 -0
- data/app/views/spree/webhook_mailer/endpoint_disabled.liquid +21 -0
- data/app/workflows/spree/carts/add_item.rb +4 -4
- data/app/workflows/spree/carts/complete.rb +13 -3
- data/app/workflows/spree/carts/merge.rb +1 -1
- data/app/workflows/spree/carts/recalculate_totals.rb +5 -0
- data/app/workflows/spree/carts/upsert_items.rb +18 -9
- data/app/workflows/spree/claims/approve.rb +5 -22
- data/app/workflows/spree/claims/cancel.rb +5 -21
- data/app/workflows/spree/claims/create.rb +15 -0
- data/app/workflows/spree/claims/deny.rb +7 -0
- data/app/workflows/spree/claims/resolve.rb +34 -31
- data/app/workflows/spree/customers/anonymize.rb +3 -4
- data/app/workflows/spree/customers/create.rb +1 -1
- data/app/workflows/spree/data_requests/fulfill.rb +2 -2
- data/app/workflows/spree/deliveries/update_tracking.rb +1 -1
- data/app/workflows/spree/email_templates/discard_draft.rb +20 -0
- data/app/workflows/spree/email_templates/publish.rb +70 -0
- data/app/workflows/spree/email_templates/restore_revision.rb +33 -0
- data/app/workflows/spree/email_templates/revert.rb +29 -0
- data/app/workflows/spree/email_templates/save_draft.rb +85 -0
- data/app/workflows/spree/exchanges/approve.rb +5 -22
- data/app/workflows/spree/exchanges/cancel.rb +5 -21
- data/app/workflows/spree/exchanges/create.rb +6 -0
- data/app/workflows/spree/exchanges/fulfill.rb +75 -51
- data/app/workflows/spree/exchanges/receive.rb +6 -65
- data/app/workflows/spree/fulfillments/cancel.rb +1 -1
- data/app/workflows/spree/fulfillments/create.rb +53 -49
- data/app/workflows/spree/fulfillments/fulfill.rb +23 -27
- data/app/workflows/spree/fulfillments/mark_delivered.rb +1 -1
- data/app/workflows/spree/fulfillments/replacements.rb +59 -0
- data/app/workflows/spree/gift_cards/apply.rb +2 -2
- data/app/workflows/spree/orders/add_item.rb +5 -1
- data/app/workflows/spree/orders/cancel.rb +3 -3
- data/app/workflows/spree/orders/complete.rb +16 -8
- data/app/workflows/spree/payments/capture.rb +20 -5
- data/app/workflows/spree/payments/process.rb +5 -3
- data/app/workflows/spree/post_sale/approval.rb +35 -0
- data/app/workflows/spree/post_sale/cancellation.rb +44 -0
- data/app/workflows/spree/post_sale/receipt.rb +92 -0
- data/app/workflows/spree/price_lists/update.rb +4 -4
- data/app/workflows/spree/products/nested_attributes.rb +1 -1
- data/app/workflows/spree/purchase_orders/cancel.rb +1 -1
- data/app/workflows/spree/purchase_orders/close.rb +3 -31
- data/app/workflows/spree/purchase_orders/create.rb +3 -1
- data/app/workflows/spree/purchase_orders/mark_draft.rb +2 -2
- data/app/workflows/spree/purchase_orders/mark_ordered.rb +2 -2
- data/app/workflows/spree/purchase_orders/receive.rb +1 -1
- data/app/workflows/spree/purchase_orders/update.rb +5 -34
- data/app/workflows/spree/receivables/closing_short.rb +46 -0
- data/app/workflows/spree/receivables/draft_editing.rb +48 -0
- data/app/workflows/spree/refunds/create.rb +5 -2
- data/app/workflows/spree/refunds/order_payments.rb +14 -2
- data/app/workflows/spree/refunds/tax_credit.rb +67 -0
- data/app/workflows/spree/returns/approve.rb +5 -22
- data/app/workflows/spree/returns/cancel.rb +5 -22
- data/app/workflows/spree/returns/create.rb +8 -0
- data/app/workflows/spree/returns/receive.rb +5 -76
- data/app/workflows/spree/returns/refund.rb +31 -8
- data/app/workflows/spree/seller_requirement_submissions/create.rb +1 -2
- data/app/workflows/spree/seller_transfers/reverse.rb +28 -1
- data/app/workflows/spree/shipping_labels/purchase.rb +8 -8
- data/app/workflows/spree/shipping_labels/record.rb +7 -7
- data/app/workflows/spree/shipping_labels/refund.rb +2 -2
- data/app/workflows/spree/stock_receipts/recording.rb +4 -4
- data/app/workflows/spree/stock_transfers/cancel.rb +2 -2
- data/app/workflows/spree/stock_transfers/close.rb +3 -30
- data/app/workflows/spree/stock_transfers/create.rb +3 -1
- data/app/workflows/spree/stock_transfers/mark_draft.rb +1 -1
- data/app/workflows/spree/stock_transfers/mark_in_transit.rb +3 -3
- data/app/workflows/spree/stock_transfers/mark_ready.rb +2 -2
- data/app/workflows/spree/stock_transfers/receive.rb +1 -1
- data/app/workflows/spree/stock_transfers/update.rb +5 -33
- data/config/currency_exponents.json +180 -0
- data/config/i18n-tasks.yml +32 -18
- data/config/initializers/alba.rb +7 -0
- data/config/language_names.csv +264 -0
- data/config/locales/ar.yml +811 -0
- data/config/locales/be.yml +855 -0
- data/config/locales/bg.yml +723 -0
- data/config/locales/ca.yml +689 -0
- data/config/locales/content_locales.rb +9 -0
- data/config/locales/cs.yml +855 -0
- data/config/locales/da.yml +771 -0
- data/config/locales/de-CH.yml +248 -0
- data/config/locales/de.yml +835 -0
- data/config/locales/el.yml +769 -0
- data/config/locales/en.yml +47 -505
- data/config/locales/es-CL.yml +301 -0
- data/config/locales/es-EC.yml +186 -0
- data/config/locales/es-MX.yml +334 -0
- data/config/locales/es.yml +831 -0
- data/config/locales/et.yml +644 -0
- data/config/locales/fa.yml +709 -0
- data/config/locales/fi.yml +771 -0
- data/config/locales/fr.yml +830 -0
- data/config/locales/hu.yml +751 -0
- data/config/locales/id.yml +756 -0
- data/config/locales/it.yml +833 -0
- data/config/locales/ja.yml +726 -0
- data/config/locales/km.yml +759 -0
- data/config/locales/ko.yml +575 -0
- data/config/locales/ku.yml +753 -0
- data/config/locales/lt.yml +821 -0
- data/config/locales/lv.yml +685 -0
- data/config/locales/nb.yml +824 -0
- data/config/locales/ne.yml +823 -0
- data/config/locales/nl.yml +826 -0
- data/config/locales/pl.yml +835 -0
- data/config/locales/pt-BR.yml +547 -0
- data/config/locales/pt.yml +636 -0
- data/config/locales/ro.yml +750 -0
- data/config/locales/ru.yml +834 -0
- data/config/locales/sk.yml +680 -0
- data/config/locales/sl-SI.yml +600 -0
- data/config/locales/sv.yml +827 -0
- data/config/locales/th.yml +745 -0
- data/config/locales/tr.yml +777 -0
- data/config/locales/uk.yml +836 -0
- data/config/locales/vi.yml +768 -0
- data/config/locales/zh-CN.yml +786 -0
- data/config/locales/zh-TW.yml +834 -0
- data/db/migrate/20260925000001_add_replacement_to_spree_fulfillment_items.rb +5 -0
- data/db/migrate/20261001000001_add_post_sale_tax.rb +30 -0
- data/db/migrate/20261001000001_convert_preferences_to_json.rb +166 -0
- data/db/migrate/20261001000001_create_spree_email_templates.rb +52 -0
- data/db/migrate/20261009000001_change_money_columns_to_decimal_19_4.rb +116 -0
- data/db/migrate/20261010000001_add_store_id_to_active_storage_blobs.rb +12 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +0 -9
- data/lib/generators/spree/dummy/templates/rails/test.rb +26 -0
- data/lib/spree/checkout/default_requirements.rb +37 -13
- data/lib/spree/core/configuration.rb +19 -1
- data/lib/spree/core/controller_helpers/store.rb +1 -1
- data/lib/spree/core/dependencies.rb +5 -4
- data/lib/spree/core/emails/escaped_output.rb +60 -0
- data/lib/spree/core/engine.rb +72 -165
- data/lib/spree/core/permissions/default_catalog.rb +5 -0
- data/lib/spree/core/preferences/invalid_preferences.rb +18 -0
- data/lib/spree/core/preferences/json_conversion.rb +186 -0
- data/lib/spree/core/preferences/masking.rb +55 -2
- data/lib/spree/core/preferences/preferable.rb +343 -103
- data/lib/spree/core/preferences/preferable_class_methods.rb +188 -136
- data/lib/spree/core/previews/import_preview.rb +10 -0
- data/lib/spree/core/ransack_configuration.rb +13 -2
- data/lib/spree/core/tax/provider_error.rb +37 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +91 -373
- data/lib/spree/emails/editable_templates.rb +82 -0
- data/lib/spree/events/catalog.rb +189 -0
- data/lib/spree/events.rb +21 -1
- data/lib/spree/hooks.rb +0 -17
- data/lib/spree/i18n.rb +32 -15
- data/lib/spree/iso_data.rb +7 -0
- data/lib/spree/localized_number.rb +6 -0
- data/lib/spree/migrations.rb +4 -1
- data/lib/spree/money.rb +196 -15
- data/lib/spree/reporting/adapters/base.rb +7 -6
- data/lib/spree/reporting/adapters/live.rb +6 -6
- data/lib/spree/reporting/default_vocabulary.rb +22 -10
- data/lib/spree/reporting/hydration.rb +1 -1
- data/lib/spree/reporting/query.rb +8 -0
- data/lib/spree/reporting/registry.rb +13 -0
- data/lib/spree/reporting/schema.rb +10 -10
- data/lib/spree/testing_support/editable_email_templates.rb +61 -0
- data/lib/spree/testing_support/emails.rb +22 -0
- data/lib/spree/testing_support/factories/cart_factory.rb +1 -1
- data/lib/spree/testing_support/factories/email_template_factory.rb +28 -0
- data/lib/spree/testing_support/factories/order_factory.rb +2 -2
- data/lib/spree/testing_support/factories/product_factory.rb +9 -0
- data/lib/spree/testing_support/factories/refund_factory.rb +1 -1
- data/lib/spree/testing_support/factories/stock_factory.rb +1 -1
- data/lib/spree/testing_support/factories/variant_factory.rb +1 -1
- data/lib/spree/testing_support/i18n.rb +3 -94
- data/lib/spree/testing_support/lifecycle_events.rb +1 -1
- data/lib/spree/testing_support/order_walkthrough.rb +1 -1
- data/lib/spree/testing_support/preferences.rb +0 -5
- data/lib/spree/testing_support/store.rb +9 -1
- data/lib/spree/upgrades/5_6_to_6_0/manifest.yml +67 -1
- data/lib/spree/uploads.rb +101 -0
- data/lib/tasks/categories_and_collections.rake +3 -3
- data/lib/tasks/core.rake +6 -4
- data/lib/tasks/markets.rake +2 -1
- data/lib/tasks/media.rake +3 -3
- data/lib/tasks/migrate_users_to_customers.rake +23 -18
- data/lib/tasks/money.rake +46 -0
- data/lib/tasks/package_types.rake +1 -1
- data/lib/tasks/preferences_json.rake +101 -0
- data/lib/tasks/seller_sample_data.rake +2 -2
- data/lib/tasks/store_settings.rake +13 -6
- data/lib/tasks/typed_adjustments_migration.rake +1 -1
- data/lib/tasks/uploads.rake +19 -0
- data/spec/fixtures/mailer_views/custom_views_probe_mailer/welcome_email.html.erb +4 -0
- metadata +219 -46
- data/app/jobs/spree/products/touch_categories_job.rb +0 -15
- data/app/jobs/spree/products/touch_taxons_job.rb +0 -13
- data/app/models/acts_as_taggable_on/tag_decorator.rb +0 -10
- data/app/models/concerns/spree/has_image_alt_text.rb +0 -18
- data/app/models/spree/base_analytics_event_handler.rb +0 -54
- data/app/models/spree/invitations/store.rb +0 -6
- data/app/models/spree/preference.rb +0 -14
- data/app/models/spree/promotion_handler/page.rb +0 -25
- data/app/models/spree/promotion_handler/promotion_duplicator.rb +0 -60
- data/app/models/spree/stock/differentiator.rb +0 -45
- data/app/presenters/spree/filters/options_presenter.rb +0 -47
- data/app/services/spree/carts/empty.rb +0 -42
- data/app/services/spree/country_to_timezone.rb +0 -273
- data/app/services/spree/payments/create.rb +0 -92
- data/app/validators/spree/url_validator.rb +0 -23
- data/app/views/active_storage/blobs/_blob.html.erb +0 -14
- data/app/views/spree/admin_user_mailer/password_reset_email.html.erb +0 -8
- data/app/views/spree/export_mailer/export_done.html.erb +0 -7
- data/app/views/spree/import_mailer/import_done.html.erb +0 -12
- data/app/views/spree/invitation_mailer/invitation_accepted.html.erb +0 -4
- data/app/views/spree/invitation_mailer/invitation_email.html.erb +0 -12
- data/app/views/spree/seller_user_mailer/password_reset_email.html.erb +0 -8
- data/app/views/spree/shared/_base_mailer_footer.html.erb +0 -19
- data/app/views/spree/shared/_base_mailer_header.html.erb +0 -8
- data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +0 -399
- data/app/views/spree/shared/_mailer_logo.html.erb +0 -41
- data/app/views/spree/shared/_purchased_items_styles.html.erb +0 -119
- data/app/views/spree/webhook_mailer/endpoint_disabled.html.erb +0 -51
- data/app/views/spree/webhook_mailer/endpoint_disabled.text.erb +0 -10
- data/app/workflows/spree/fulfillments/purchase_label.rb +0 -40
- data/app/workflows/spree/returns/purchase_label.rb +0 -32
- data/lib/spree/analytics.rb +0 -11
- data/lib/spree/core/preferences/scoped_store.rb +0 -34
- data/lib/spree/core/preferences/store.rb +0 -105
- data/lib/spree/translation_migrations.rb +0 -52
|
@@ -38,8 +38,17 @@ FactoryBot.define do
|
|
|
38
38
|
price { 19.99 }
|
|
39
39
|
compare_at_price { nil }
|
|
40
40
|
currency { nil }
|
|
41
|
+
published_at { nil }
|
|
42
|
+
unpublished_at { nil }
|
|
41
43
|
end
|
|
42
44
|
|
|
45
|
+
# The deprecated +available_on=+/+discontinue_on=+ setters warn, so the
|
|
46
|
+
# dates go straight onto the legacy columns, which code still reads and
|
|
47
|
+
# which seed the default-channel publication created below.
|
|
48
|
+
after(:build) do |product, evaluator|
|
|
49
|
+
product[:available_on] = evaluator.published_at if evaluator.published_at
|
|
50
|
+
product[:discontinue_on] = evaluator.unpublished_at if evaluator.unpublished_at
|
|
51
|
+
end
|
|
43
52
|
before(:create) do |_product|
|
|
44
53
|
create(:stock_location) unless Spree::StockLocation.any?
|
|
45
54
|
end
|
|
@@ -4,7 +4,7 @@ FactoryBot.define do
|
|
|
4
4
|
factory :refund, class: Spree::Refund do
|
|
5
5
|
amount { 100.00 }
|
|
6
6
|
transaction_id { generate(:refund_transaction_id) }
|
|
7
|
-
association(:payment,
|
|
7
|
+
association(:payment, status: 'completed')
|
|
8
8
|
association(:reason, factory: :refund_reason)
|
|
9
9
|
end
|
|
10
10
|
|
|
@@ -20,7 +20,7 @@ FactoryBot.define do
|
|
|
20
20
|
|
|
21
21
|
after(:build) do |package, evaluator|
|
|
22
22
|
evaluator.variants_contents.each do |variant, count|
|
|
23
|
-
package.add_multiple build_list(:
|
|
23
|
+
package.add_multiple build_list(:fulfillment_item, count, variant: variant)
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
|
|
@@ -1,94 +1,3 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
|
|
4
|
-
# If there is a translation referenced which has no corresponding key within the
|
|
5
|
-
# .yml file, then there will be a message output at the end of the suite showing
|
|
6
|
-
# that.
|
|
7
|
-
#
|
|
8
|
-
# If there is a translation within the locale file which *isn't* used in the
|
|
9
|
-
# test, this will also be shown at the end of the suite run.
|
|
10
|
-
module Spree
|
|
11
|
-
class << self
|
|
12
|
-
attr_accessor :used_translations, :missing_translation_messages,
|
|
13
|
-
:unused_translations, :unused_translation_messages
|
|
14
|
-
alias normal_t t
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def self.t(*args)
|
|
18
|
-
original_args = args.dup
|
|
19
|
-
options = args.extract_options!
|
|
20
|
-
self.used_translations ||= []
|
|
21
|
-
[*args.first].each do |translation_key|
|
|
22
|
-
key = ([*options[:scope]] << translation_key).join('.')
|
|
23
|
-
self.used_translations << key
|
|
24
|
-
end
|
|
25
|
-
normal_t(*original_args)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def self.check_missing_translations
|
|
29
|
-
self.missing_translation_messages = []
|
|
30
|
-
self.used_translations ||= []
|
|
31
|
-
used_translations.map { |a| a.split('.') }.each do |translation_keys|
|
|
32
|
-
root = translations
|
|
33
|
-
processed_keys = []
|
|
34
|
-
translation_keys.each do |key|
|
|
35
|
-
root = root.fetch(key.to_sym)
|
|
36
|
-
processed_keys << key.to_sym
|
|
37
|
-
rescue KeyError
|
|
38
|
-
error = "#{(processed_keys << key).join('.')} (#{I18n.locale})"
|
|
39
|
-
unless Spree.missing_translation_messages.include?(error)
|
|
40
|
-
Spree.missing_translation_messages << error
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def self.check_unused_translations
|
|
47
|
-
self.used_translations ||= []
|
|
48
|
-
self.unused_translation_messages = []
|
|
49
|
-
self.unused_translations = []
|
|
50
|
-
load_translations(translations)
|
|
51
|
-
translation_diff = unused_translations - used_translations
|
|
52
|
-
translation_diff.each do |translation|
|
|
53
|
-
Spree.unused_translation_messages << "#{translation} (#{I18n.locale})"
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
private
|
|
58
|
-
|
|
59
|
-
def self.load_translations(hash, root = [])
|
|
60
|
-
hash.each do |k, v|
|
|
61
|
-
if v.is_a?(Hash)
|
|
62
|
-
load_translations(v, root.dup << k)
|
|
63
|
-
else
|
|
64
|
-
key = (root + [k]).join('.')
|
|
65
|
-
unused_translations << key
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def self.translations
|
|
71
|
-
@translations ||= I18n.backend.send(:translations)[I18n.locale][:spree]
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
RSpec.configure do |config|
|
|
76
|
-
# Need to check here again because this is used in i18n_spec too.
|
|
77
|
-
if ENV['CHECK_TRANSLATIONS']
|
|
78
|
-
config.after :suite do
|
|
79
|
-
Spree.check_missing_translations
|
|
80
|
-
if Spree.missing_translation_messages.any?
|
|
81
|
-
puts "\nThere are missing translations within Spree:"
|
|
82
|
-
puts Spree.missing_translation_messages.sort
|
|
83
|
-
exit(1)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
Spree.check_unused_translations
|
|
87
|
-
if Spree.unused_translation_messages.any?
|
|
88
|
-
puts "\nThere are unused translations within Spree:"
|
|
89
|
-
puts Spree.unused_translation_messages.sort
|
|
90
|
-
exit(1)
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|
|
1
|
+
# Deprecated: Spree's specs now catch missing keys through Rails'
|
|
2
|
+
# config.i18n.raise_on_missing_translations. Removed in Spree 6.1.
|
|
3
|
+
Spree::Deprecation.warn("spree/testing_support/i18n is deprecated and does nothing; set config.i18n.raise_on_missing_translations = true in your test environment instead. It will be removed in Spree 6.1.") if defined?(Spree::Deprecation)
|
|
@@ -21,7 +21,7 @@ shared_examples_for 'lifecycle events' do |factory: nil, event_prefix: nil|
|
|
|
21
21
|
expect(record).to receive(:publish_event).with("#{lifecycle_event_prefix}.updated")
|
|
22
22
|
allow(record).to receive(:publish_event).with(anything)
|
|
23
23
|
|
|
24
|
-
# update_attribute, not update!: Spree::
|
|
24
|
+
# update_attribute, not update!: Spree::Fulfillment#update! shadows the
|
|
25
25
|
# Active Record method with the legacy state-recalculation API.
|
|
26
26
|
Timecop.travel(1.minute.from_now) do
|
|
27
27
|
record.update_attribute(:updated_at, Time.current)
|
|
@@ -21,7 +21,7 @@ class OrderWalkthrough
|
|
|
21
21
|
|
|
22
22
|
# A delivery method must exist for rates to be displayed on checkout page
|
|
23
23
|
unless Spree::DeliveryMethod.exists?
|
|
24
|
-
FactoryBot.create(:
|
|
24
|
+
FactoryBot.create(:delivery_method).tap do |delivery_method|
|
|
25
25
|
delivery_method.calculator.preferred_amount = 10
|
|
26
26
|
delivery_method.calculator.preferred_currency = store.default_currency
|
|
27
27
|
delivery_method.calculator.save
|
|
@@ -18,11 +18,6 @@ module Spree
|
|
|
18
18
|
yield(config) if block_given?
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def assert_preference_unset(preference)
|
|
22
|
-
find("#preferences_#{preference}")['checked'].should be false
|
|
23
|
-
Spree::Config[preference].should be false
|
|
24
|
-
end
|
|
25
|
-
|
|
26
21
|
# Stubs store-scoped commerce settings for the duration of one example.
|
|
27
22
|
#
|
|
28
23
|
# stub_store_preferences(track_inventory_levels: false)
|
|
@@ -29,6 +29,15 @@ RSpec.configure do |config|
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# Reloaded before each example rather than after: the after hooks run
|
|
33
|
+
# inside the example's transaction, so a reload there still sees the
|
|
34
|
+
# example's writes, and the next example would start from values the
|
|
35
|
+
# database no longer holds. Setting a preference to such a stale value is
|
|
36
|
+
# no change to Rails, so it would never be saved.
|
|
37
|
+
config.before(:each) do
|
|
38
|
+
@default_store&.reload unless self.class.metadata[:without_global_store]
|
|
39
|
+
end
|
|
40
|
+
|
|
32
41
|
config.after(:each) do
|
|
33
42
|
unless self.class.metadata[:without_global_store]
|
|
34
43
|
@default_store&.products = []
|
|
@@ -43,7 +52,6 @@ RSpec.configure do |config|
|
|
|
43
52
|
@default_store.association(:default_market).reset if @default_store.association_cached?(:default_market)
|
|
44
53
|
@default_store.association(:markets).reset if @default_store.association_cached?(:markets)
|
|
45
54
|
@default_store.remove_instance_variable(:@has_markets) if @default_store.instance_variable_defined?(:@has_markets)
|
|
46
|
-
@default_store.reload
|
|
47
55
|
end
|
|
48
56
|
end
|
|
49
57
|
end
|
|
@@ -35,6 +35,22 @@ steps:
|
|
|
35
35
|
|
|
36
36
|
Idempotent, and a no-op on an already-consolidated schema.
|
|
37
37
|
|
|
38
|
+
- id: preferences_json
|
|
39
|
+
name: "Check for preferences still stored as YAML"
|
|
40
|
+
task: "spree:upgrade:preferences_json"
|
|
41
|
+
notes: |
|
|
42
|
+
Spree 6.0 stores preferences as JSON instead of YAML, and keeps secrets
|
|
43
|
+
(preferences declared as passwords, such as gateway API keys) in a
|
|
44
|
+
separate secret_preferences column. The migration converts every row and
|
|
45
|
+
moves every secret itself, so a normal db:migrate needs nothing from this
|
|
46
|
+
step.
|
|
47
|
+
|
|
48
|
+
This is a safety net: it converts any row still holding YAML, and moves
|
|
49
|
+
the secrets of a class that was not loaded when the migration ran, such
|
|
50
|
+
as one from an extension gem installed afterwards.
|
|
51
|
+
|
|
52
|
+
Idempotent, and a no-op once everything is converted.
|
|
53
|
+
|
|
38
54
|
- id: migrate_media_class_names
|
|
39
55
|
name: "Rewrite stored Spree::Asset and Spree::Image class names"
|
|
40
56
|
task: "spree:migrate_media_class_names"
|
|
@@ -149,7 +165,9 @@ steps:
|
|
|
149
165
|
that has_secure_password reads directly only when unpeppered; the task
|
|
150
166
|
aborts if Devise.pepper is set. Because Devise is gone in 6.0 a former
|
|
151
167
|
pepper can't be introspected, so when Devise is absent the task aborts until
|
|
152
|
-
you confirm none was used with CONFIRM_NO_PEPPER=true.
|
|
168
|
+
you confirm none was used with CONFIRM_NO_PEPPER=true. The check is skipped
|
|
169
|
+
when there are no passwords to copy (e.g. an empty spree_users table), so
|
|
170
|
+
new projects pass without the flag. Peppered / SSO /
|
|
153
171
|
non-bcrypt installs keep a custom customer_class instead (see the 5.6-to-6.0
|
|
154
172
|
upgrade guide) and skip this step.
|
|
155
173
|
|
|
@@ -288,6 +306,20 @@ steps:
|
|
|
288
306
|
with one statement scoped to the rows still missing a code, so an
|
|
289
307
|
interrupted run picks up where it stopped.
|
|
290
308
|
|
|
309
|
+
- id: migrate_checkout_zones
|
|
310
|
+
name: "Convert checkout zones to markets"
|
|
311
|
+
task: "spree:markets:migrate_checkout_zones"
|
|
312
|
+
notes: |
|
|
313
|
+
Markets replace the store's checkout zone in Spree 6. Stores that have
|
|
314
|
+
no market yet get a default one covering their checkout zone's
|
|
315
|
+
countries, or their default country when no zone was set, and the
|
|
316
|
+
checkout zone is cleared.
|
|
317
|
+
|
|
318
|
+
Run before migrate_tax_zones, which matches zone price rules against a
|
|
319
|
+
store's markets, and before backfill_order_markets, which assigns each
|
|
320
|
+
store's default market to its orders. Idempotent: stores that already
|
|
321
|
+
have a market are skipped.
|
|
322
|
+
|
|
291
323
|
- id: migrate_promotion_option_value_rules
|
|
292
324
|
name: "Rewrite Option Value promotion rules to stable option value ids"
|
|
293
325
|
task: "spree:upgrade:migrate_promotion_option_value_rules"
|
|
@@ -715,3 +747,37 @@ steps:
|
|
|
715
747
|
predates the upgrade.
|
|
716
748
|
|
|
717
749
|
Idempotent, and safe to re-run at any time to repair drift.
|
|
750
|
+
|
|
751
|
+
- id: encrypt_secret_preferences
|
|
752
|
+
name: "Encrypt gateway and integration secrets"
|
|
753
|
+
task: "spree:upgrade:encrypt_secret_preferences"
|
|
754
|
+
notes: |
|
|
755
|
+
The 6.0 migration moves existing secrets into the secret_preferences
|
|
756
|
+
column in plain text, so it never needs encryption keys. They stay
|
|
757
|
+
readable and are encrypted the next time their record is saved. This step
|
|
758
|
+
encrypts them all now.
|
|
759
|
+
|
|
760
|
+
Skips with a note when Active Record encryption keys are not configured;
|
|
761
|
+
see the encryption section of the upgrade guide to add them, then run
|
|
762
|
+
this step again.
|
|
763
|
+
|
|
764
|
+
Idempotent.
|
|
765
|
+
|
|
766
|
+
- id: assign_upload_stores
|
|
767
|
+
name: "Record which store owns every uploaded file"
|
|
768
|
+
task: "spree:uploads:assign_stores"
|
|
769
|
+
notes: |
|
|
770
|
+
Spree 6.0 records the store that owns every uploaded file, so a file from
|
|
771
|
+
one store cannot be attached in another and storage can be measured and
|
|
772
|
+
cleaned up per store. New files get their store when they are uploaded;
|
|
773
|
+
this gives existing files the store of the record they are attached to.
|
|
774
|
+
|
|
775
|
+
Files attached in more than one store are listed and left unchanged for
|
|
776
|
+
you to resolve. Files attached to nothing keep no store and are left
|
|
777
|
+
alone: the daily purge of never-attached uploads
|
|
778
|
+
(Spree::Uploads::PurgeUnattachedJob, see the upgrade guide) only
|
|
779
|
+
deletes files that belong to a store.
|
|
780
|
+
|
|
781
|
+
Run AFTER the steps that create or move attachments (media, categories,
|
|
782
|
+
returns), so their files are covered. Idempotent — files that already
|
|
783
|
+
have a store are skipped.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
# Store ownership of uploaded files (docs/plans/6.0-uploads-and-file-ownership.md).
|
|
3
|
+
#
|
|
4
|
+
# Every `ActiveStorage::Blob` records the store that owns it, and attaching a
|
|
5
|
+
# blob to a record of another store is reported. Spree 6.0 only logs; 6.1
|
|
6
|
+
# refuses, so one release of logs finds every path that still creates blobs
|
|
7
|
+
# without a store.
|
|
8
|
+
module Uploads
|
|
9
|
+
# How long an upload reference (`signed_id`) stays attachable.
|
|
10
|
+
SIGNED_ID_EXPIRY = 1.day
|
|
11
|
+
|
|
12
|
+
# Mints an expiring upload reference for +blob+.
|
|
13
|
+
#
|
|
14
|
+
# @param blob [ActiveStorage::Blob]
|
|
15
|
+
# @return [String] an opaque reference clients pass back unchanged
|
|
16
|
+
def self.signed_id_for(blob)
|
|
17
|
+
blob.signed_id(expires_in: SIGNED_ID_EXPIRY)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# The store owning +record+, or nil for records that belong to no store
|
|
21
|
+
# (admin users, customers).
|
|
22
|
+
#
|
|
23
|
+
# @param record [ActiveRecord::Base]
|
|
24
|
+
# @return [Integer, String, nil]
|
|
25
|
+
def self.store_id_for(record)
|
|
26
|
+
return record.id if record.is_a?(Spree::Store)
|
|
27
|
+
# A processed rendition belongs to whoever owns its original.
|
|
28
|
+
return record.blob&.store_id if record.is_a?(ActiveStorage::VariantRecord)
|
|
29
|
+
return record.store_id if record.has_attribute?(:store_id)
|
|
30
|
+
|
|
31
|
+
record.try(:store)&.id
|
|
32
|
+
rescue Module::DelegationError
|
|
33
|
+
# An owner whose parent is gone (a digital asset on a deleted variant)
|
|
34
|
+
# has no store to compare against.
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
module BlobStoreOwnership
|
|
39
|
+
extend ActiveSupport::Concern
|
|
40
|
+
|
|
41
|
+
included do
|
|
42
|
+
before_create :assign_current_store
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
# Reads the store a request or job declared, never the default-store
|
|
48
|
+
# fallback: guessing the default would hide exactly the creation paths
|
|
49
|
+
# the 6.0 logs are meant to find.
|
|
50
|
+
def assign_current_store
|
|
51
|
+
return unless has_attribute?(:store_id)
|
|
52
|
+
|
|
53
|
+
self.store_id ||= Spree::Current.attributes[:store]&.id
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
module AttachmentStoreCheck
|
|
58
|
+
extend ActiveSupport::Concern
|
|
59
|
+
|
|
60
|
+
included do
|
|
61
|
+
before_validation :adopt_owner_store, on: :create
|
|
62
|
+
after_create :check_blob_store
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
# A file Spree just made from bytes it holds (an export, a purchased
|
|
68
|
+
# label) is created in the same call that attaches it, so it simply
|
|
69
|
+
# takes its owner's store, written with the file itself.
|
|
70
|
+
def adopt_owner_store
|
|
71
|
+
return unless blob&.new_record? && blob.has_attribute?(:store_id) && record
|
|
72
|
+
|
|
73
|
+
blob.store_id ||= owner_store_id
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def check_blob_store
|
|
77
|
+
return unless blob&.has_attribute?(:store_id) && record
|
|
78
|
+
return if owner_store_id.nil?
|
|
79
|
+
|
|
80
|
+
if blob.store_id.nil?
|
|
81
|
+
report_store_mismatch('has no store')
|
|
82
|
+
elsif blob.store_id.to_s != owner_store_id.to_s
|
|
83
|
+
report_store_mismatch("belongs to store #{blob.store_id}")
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def owner_store_id
|
|
88
|
+
return @owner_store_id if defined?(@owner_store_id)
|
|
89
|
+
|
|
90
|
+
@owner_store_id = Spree::Uploads.store_id_for(record)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def report_store_mismatch(reason)
|
|
94
|
+
Rails.logger.warn(
|
|
95
|
+
"[Spree] Attached file #{blob.id} #{reason}, but #{record_type}##{record_id} (#{name}) " \
|
|
96
|
+
"belongs to store #{owner_store_id}. Spree 6.1 refuses this attachment."
|
|
97
|
+
)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -80,7 +80,7 @@ namespace :spree do
|
|
|
80
80
|
# otherwise purge/destroy: ActionText description, images, custom fields, slugs.
|
|
81
81
|
move_polymorphic.call(ActionText::RichText, :record_type, :record_id, category, collection)
|
|
82
82
|
move_polymorphic.call(ActiveStorage::Attachment, :record_type, :record_id, category, collection, name: %w[image square_image])
|
|
83
|
-
move_polymorphic.call(Spree::
|
|
83
|
+
move_polymorphic.call(Spree::CustomField, :resource_type, :resource_id, category, collection)
|
|
84
84
|
move_polymorphic.call(FriendlyId::Slug, :sluggable_type, :sluggable_id, category, collection)
|
|
85
85
|
|
|
86
86
|
# Rules -> collection_rules (remap the STI type; insert_all bypasses the
|
|
@@ -169,8 +169,8 @@ namespace :spree do
|
|
|
169
169
|
# category rows that still hold the pre-6.0 names.
|
|
170
170
|
puts 'Backfilling renamed class-name strings...'
|
|
171
171
|
[
|
|
172
|
-
[Spree::
|
|
173
|
-
[Spree::
|
|
172
|
+
[Spree::CustomField, :resource_type, 'Spree::Taxon', 'Spree::Category'],
|
|
173
|
+
[Spree::CustomFieldDefinition, :resource_type, 'Spree::Taxon', 'Spree::Category'],
|
|
174
174
|
[ActiveStorage::Attachment, :record_type, 'Spree::Taxon', 'Spree::Category'],
|
|
175
175
|
# description is an ActionText field (translates :description, backend: :action_text);
|
|
176
176
|
# surviving categories keep their rich-text description without this.
|
data/lib/tasks/core.rake
CHANGED
|
@@ -26,14 +26,16 @@ namespace :core do
|
|
|
26
26
|
|
|
27
27
|
desc 'Migrate newsletter subscribers'
|
|
28
28
|
task migrate_newsletter_subscribers: :environment do |_t, _args|
|
|
29
|
-
Spree.
|
|
30
|
-
|
|
29
|
+
store_id = Spree::Store.default&.id
|
|
30
|
+
|
|
31
|
+
Spree.customer_class.where(accepts_email_marketing: true).in_batches(of: 500) do |customer_batch|
|
|
32
|
+
subscriber_attributes = customer_batch.pluck(:id, :email, :updated_at).map do |id, email, updated_at|
|
|
31
33
|
{
|
|
32
34
|
email: Spree::NewsletterSubscriber.new(email: email).email, # normalized email
|
|
33
|
-
|
|
35
|
+
customer_id: id,
|
|
34
36
|
verified_at: updated_at,
|
|
35
37
|
verification_token: nil,
|
|
36
|
-
store_id:
|
|
38
|
+
store_id: store_id,
|
|
37
39
|
updated_at: DateTime.current,
|
|
38
40
|
created_at: DateTime.current
|
|
39
41
|
}
|
data/lib/tasks/markets.rake
CHANGED
|
@@ -31,7 +31,8 @@ namespace :spree do
|
|
|
31
31
|
market = store.markets.create!(
|
|
32
32
|
name: primary_country&.name || 'Default',
|
|
33
33
|
currency: iso_country&.currency_code || store.read_attribute(:default_currency) || 'USD',
|
|
34
|
-
default_locale: iso_country&.languages_official&.first
|
|
34
|
+
default_locale: Spree::Locales.listed(iso_country&.languages_official&.first) ||
|
|
35
|
+
Spree::Locales.listed(store.read_attribute(:default_locale)) || 'en',
|
|
35
36
|
default: true,
|
|
36
37
|
countries: countries
|
|
37
38
|
)
|
data/lib/tasks/media.rake
CHANGED
|
@@ -31,9 +31,9 @@ namespace :spree do
|
|
|
31
31
|
# Subquery (not pluck) so the product set doesn't materialize in Ruby —
|
|
32
32
|
# important for catalogs with millions of products.
|
|
33
33
|
variant_product_ids = Spree::Variant
|
|
34
|
-
.joins("INNER JOIN #{Spree::
|
|
35
|
-
"#{Spree::
|
|
36
|
-
"AND #{Spree::
|
|
34
|
+
.joins("INNER JOIN #{Spree::Media.table_name} ON " \
|
|
35
|
+
"#{Spree::Media.table_name}.viewable_id = #{Spree::Variant.table_name}.id " \
|
|
36
|
+
"AND #{Spree::Media.table_name}.viewable_type = 'Spree::Variant'")
|
|
37
37
|
.select(:product_id)
|
|
38
38
|
|
|
39
39
|
relation = Spree::Product.where(id: variant_product_ids)
|
|
@@ -16,7 +16,8 @@ namespace :spree do
|
|
|
16
16
|
configured — Devise's +encrypted_password+ is a plain bcrypt digest, the
|
|
17
17
|
exact format +has_secure_password+ reads. The task aborts if a pepper is
|
|
18
18
|
detected; when Devise is absent (so a former pepper can't be introspected)
|
|
19
|
-
it aborts until you confirm none was used with CONFIRM_NO_PEPPER=true.
|
|
19
|
+
it aborts until you confirm none was used with CONFIRM_NO_PEPPER=true. The
|
|
20
|
+
check is skipped when there are no passwords to copy.
|
|
20
21
|
Source rows with a blank email, or whose email is already taken by a
|
|
21
22
|
different customer, abort the task with their ids — reconcile them or pass
|
|
22
23
|
SKIP_INVALID_ROWS=true to skip and continue. The legacy source table is
|
|
@@ -38,10 +39,29 @@ namespace :spree do
|
|
|
38
39
|
next
|
|
39
40
|
end
|
|
40
41
|
|
|
42
|
+
customer_model = Spree.customer_class
|
|
43
|
+
admin_model = Spree.admin_user_class
|
|
44
|
+
|
|
45
|
+
# Read the legacy table by name only — the Devise-era Spree::User /
|
|
46
|
+
# Spree::LegacyUser models are gone in 6.0. Inherit from Spree.base_class
|
|
47
|
+
# so the source shares the customer table's connection (the id-exclusion
|
|
48
|
+
# subquery below spans both).
|
|
49
|
+
source = Class.new(Spree.base_class) { self.table_name = source_table }
|
|
50
|
+
|
|
51
|
+
pending = source.where.not(id: customer_model.select(:id))
|
|
52
|
+
admin_pending = if admin_model.column_names.include?('encrypted_password')
|
|
53
|
+
admin_model.where(password_digest: [nil, '']).where.not(encrypted_password: [nil, ''])
|
|
54
|
+
else
|
|
55
|
+
admin_model.none
|
|
56
|
+
end
|
|
57
|
+
|
|
41
58
|
# Peppered digests can't be verified by has_secure_password. Refuse rather
|
|
42
59
|
# than silently produce accounts nobody can sign into. Once Devise is gone
|
|
43
60
|
# a former pepper can't be introspected, so require an explicit all-clear.
|
|
44
|
-
|
|
61
|
+
# With no digest to copy (e.g. an empty legacy table) there is nothing to protect.
|
|
62
|
+
if pending.none? && admin_pending.none?
|
|
63
|
+
puts " No customer or admin passwords to copy — skipping the Devise pepper check."
|
|
64
|
+
elsif defined?(Devise) && Devise.respond_to?(:pepper) && Devise.pepper.present?
|
|
45
65
|
abort " Devise.pepper is configured — bcrypt digests can't be copied into password_digest. " \
|
|
46
66
|
"Use the custom-model path (keep the table, alias password_digest) or force password resets."
|
|
47
67
|
elsif !defined?(Devise) && ENV['CONFIRM_NO_PEPPER'] != 'true'
|
|
@@ -51,15 +71,6 @@ namespace :spree do
|
|
|
51
71
|
"used no pepper, or use the custom-model path / force password resets."
|
|
52
72
|
end
|
|
53
73
|
|
|
54
|
-
customer_model = Spree.customer_class
|
|
55
|
-
admin_model = Spree.admin_user_class
|
|
56
|
-
|
|
57
|
-
# Read the legacy table by name only — the Devise-era Spree::User /
|
|
58
|
-
# Spree::LegacyUser models are gone in 6.0. Inherit from Spree.base_class
|
|
59
|
-
# so the source shares the customer table's connection (the id-exclusion
|
|
60
|
-
# subquery below spans both).
|
|
61
|
-
source = Class.new(Spree.base_class) { self.table_name = source_table }
|
|
62
|
-
|
|
63
74
|
# Copy only columns both tables share; map the digest column separately.
|
|
64
75
|
direct_columns = customer_model.column_names & source.column_names
|
|
65
76
|
copy_digest_from_encrypted = source.column_names.include?('encrypted_password') &&
|
|
@@ -75,7 +86,6 @@ namespace :spree do
|
|
|
75
86
|
# the whole batch on the unique-email index.
|
|
76
87
|
# Either kind aborts the task with the offending ids unless the operator
|
|
77
88
|
# passes SKIP_INVALID_ROWS=true to skip them and continue.
|
|
78
|
-
pending = source.where.not(id: customer_model.select(:id))
|
|
79
89
|
blank_email_ids = pending.where("email IS NULL OR email = ''").pluck(:id)
|
|
80
90
|
# Compare case-insensitively to match Spree::Customer's uniqueness
|
|
81
91
|
# (case_sensitive: false) — emails are stored case-preserved, so a legacy
|
|
@@ -140,12 +150,7 @@ namespace :spree do
|
|
|
140
150
|
|
|
141
151
|
# Admins stay in spree_admin_users (in place) — backfill the digest from
|
|
142
152
|
# the legacy column when present.
|
|
143
|
-
admin_backfilled =
|
|
144
|
-
if admin_model.column_names.include?('encrypted_password')
|
|
145
|
-
admin_backfilled = admin_model.where(password_digest: [nil, '']).
|
|
146
|
-
where.not(encrypted_password: [nil, '']).
|
|
147
|
-
update_all('password_digest = encrypted_password')
|
|
148
|
-
end
|
|
153
|
+
admin_backfilled = admin_pending.update_all('password_digest = encrypted_password')
|
|
149
154
|
|
|
150
155
|
puts
|
|
151
156
|
puts " Customers copied: #{copied} (skipped #{invalid_ids.size} invalid row(s): " \
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
namespace :spree do
|
|
2
|
+
namespace :money do
|
|
3
|
+
desc <<~DESC
|
|
4
|
+
Lists payment capture events in currencies without two decimals (yen,
|
|
5
|
+
dinar, ...) and writes nothing (Spree 6.0).
|
|
6
|
+
|
|
7
|
+
Before 6.0 a partial or manual capture recorded its amount in the wrong
|
|
8
|
+
unit for these currencies: a 1000 JPY capture was recorded as 100000,
|
|
9
|
+
a 1.500 KWD capture as 0.150. A purchase (authorize and capture in one)
|
|
10
|
+
recorded the right amount, and the two cannot be told apart from the
|
|
11
|
+
row, so every event is listed with both readings: as recorded, and
|
|
12
|
+
corrected as if the capture flow wrote it. Compare them with the
|
|
13
|
+
gateway's own records before changing anything.
|
|
14
|
+
DESC
|
|
15
|
+
task audit_capture_events: :environment do
|
|
16
|
+
listed = 0
|
|
17
|
+
# The wrong records were written with the Money gem's exponents as they
|
|
18
|
+
# were before 6.0, which differ from ISO 4217 for a few currencies.
|
|
19
|
+
legacy_exponents = { 'HUF' => 0, 'MGA' => 1, 'MRO' => 1, 'MRU' => 1 }
|
|
20
|
+
exponent_for = ->(code) { legacy_exponents.fetch(code) { Spree::Money::Rounding.precision(code) } }
|
|
21
|
+
codes = (Spree::Money::Rounding::EXPONENTS.keys | legacy_exponents.keys).reject { |code| exponent_for.(code) == 2 }
|
|
22
|
+
in_codes = [Spree::Order, Spree::Cart, Spree::OrderGroup].map { |owner| owner.arel_table[:currency].in(codes) }.reduce(:or)
|
|
23
|
+
|
|
24
|
+
Spree::PaymentCaptureEvent.left_joins(payment: [:order, :cart, :order_group]).where(in_codes)
|
|
25
|
+
.includes(payment: [:order, :cart, :order_group]).find_each do |event|
|
|
26
|
+
payment = event.payment
|
|
27
|
+
next if payment.nil?
|
|
28
|
+
|
|
29
|
+
exponent = exponent_for.(payment.currency.to_s.upcase)
|
|
30
|
+
|
|
31
|
+
corrected = event.amount * (10**exponent) / 100
|
|
32
|
+
puts [
|
|
33
|
+
event.prefixed_id,
|
|
34
|
+
payment.number,
|
|
35
|
+
payment.currency,
|
|
36
|
+
"recorded=#{Spree::Money::Rounding.format(event.amount, payment.currency)}",
|
|
37
|
+
"if_from_capture=#{Spree::Money::Rounding.format(corrected, payment.currency)}",
|
|
38
|
+
"payment_amount=#{Spree::Money::Rounding.format(payment.amount, payment.currency)}"
|
|
39
|
+
].join("\t")
|
|
40
|
+
listed += 1
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
puts " #{listed} capture event(s) in currencies without two decimals. Nothing was changed."
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|