spree_core 5.6.1 → 6.0.0.beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +30 -0
- data/README.md +2 -3
- data/app/finders/spree/line_items/find_by_variant.rb +5 -3
- data/app/finders/spree/sellers/panel_url.rb +47 -0
- data/app/finders/spree/stores/dashboard_url.rb +76 -0
- data/app/helpers/spree/images_helper.rb +1 -1
- data/app/jobs/spree/carts/reap_expired_job.rb +43 -0
- data/app/jobs/spree/collections/regenerate_time_based_job.rb +18 -0
- data/app/jobs/spree/data_requests/process_job.rb +42 -0
- data/app/jobs/spree/events/subscriber_job.rb +1 -1
- data/app/jobs/spree/images/migrate_product_media_job.rb +80 -0
- data/app/jobs/spree/images/save_from_url_job.rb +70 -13
- data/app/jobs/spree/imports/create_categories_job.rb +23 -14
- data/app/jobs/spree/imports/create_rows_job.rb +3 -62
- data/app/jobs/spree/imports/process_group_job.rb +1 -1
- data/app/jobs/spree/imports/process_job.rb +164 -0
- data/app/jobs/spree/imports/process_rows_job.rb +4 -71
- data/app/jobs/spree/orders/finalize_stale_drafts_job.rb +29 -0
- data/app/jobs/spree/payments/handle_webhook_job.rb +1 -1
- data/app/jobs/spree/price_lists/sync_currencies_job.rb +42 -0
- data/app/jobs/spree/product_types/apply_to_products_job.rb +74 -0
- data/app/jobs/spree/products/auto_match_collections_job.rb +14 -0
- data/app/jobs/spree/products/auto_match_taxons_job.rb +6 -7
- data/app/jobs/spree/products/refresh_metrics_job.rb +1 -1
- data/app/jobs/spree/products/touch_categories_job.rb +15 -0
- data/app/jobs/spree/products/touch_taxons_job.rb +7 -6
- data/app/jobs/spree/sample_data/load_job.rb +13 -0
- data/app/jobs/spree/seller_payouts/sweep_due_job.rb +57 -0
- data/app/jobs/spree/seller_payouts/sweep_seller_job.rb +70 -0
- data/app/jobs/spree/seller_transfers/execute_pending_due_job.rb +56 -0
- data/app/jobs/spree/seller_transfers/execute_pending_job.rb +52 -0
- data/app/jobs/spree/shipping_labels/store_file_job.rb +17 -0
- data/app/jobs/spree/stock_locations/stock_items/create_job.rb +7 -5
- data/app/jobs/spree/stock_locations/stock_levels/create_job.rb +13 -0
- data/app/jobs/spree/stock_reservations/expire_job.rb +1 -1
- data/app/jobs/spree/tax_identifiers/validate_job.rb +14 -0
- data/app/jobs/spree/variants/remove_line_item_job.rb +29 -1
- data/app/mailers/spree/admin_user_mailer.rb +6 -35
- data/app/mailers/spree/base_mailer.rb +1 -20
- data/app/mailers/spree/invitation_mailer.rb +1 -1
- data/app/mailers/spree/seller_user_mailer.rb +47 -0
- data/app/models/concerns/spree/account_lockout.rb +38 -0
- data/app/models/concerns/spree/acted_by.rb +210 -0
- data/app/models/concerns/spree/actor.rb +51 -0
- data/app/models/concerns/spree/admin_user_methods.rb +53 -42
- data/app/models/concerns/spree/calculated_adjustments.rb +8 -14
- data/app/models/concerns/spree/calculator/currency_amounts.rb +43 -0
- data/app/models/concerns/spree/capture_method.rb +33 -0
- data/app/models/concerns/spree/custom_field_filterable.rb +163 -0
- data/app/models/concerns/spree/customer_methods.rb +421 -0
- data/app/models/concerns/spree/deprecated_customer_alias.rb +22 -0
- data/app/models/concerns/spree/derived_number.rb +66 -0
- data/app/models/concerns/spree/has_address_book.rb +89 -0
- data/app/models/concerns/spree/has_custom_fields.rb +360 -0
- data/app/models/concerns/spree/has_external_references.rb +95 -0
- data/app/models/concerns/spree/has_iso_geography.rb +71 -0
- data/app/models/concerns/spree/has_library_media.rb +94 -0
- data/app/models/concerns/spree/has_list_position.rb +15 -0
- data/app/models/concerns/spree/has_number.rb +139 -0
- data/app/models/concerns/spree/has_status.rb +76 -0
- data/app/models/concerns/spree/has_tracking_carrier.rb +18 -0
- data/app/models/concerns/spree/instruments_gateway_calls.rb +20 -0
- data/app/models/concerns/spree/integration_backed_provider.rb +89 -0
- data/app/models/concerns/spree/integrations_concern.rb +15 -2
- data/app/models/concerns/spree/label_translatable.rb +37 -0
- data/app/models/concerns/spree/marketplace/order_group.rb +35 -0
- data/app/models/concerns/spree/metadata.rb +18 -22
- data/app/models/concerns/spree/named_type.rb +11 -1
- data/app/models/concerns/spree/parameterizable_name.rb +5 -5
- data/app/models/concerns/spree/password_policy.rb +37 -0
- data/app/models/concerns/spree/payment_session_transitions.rb +93 -0
- data/app/models/concerns/spree/payment_source_concern.rb +1 -1
- data/app/models/concerns/spree/personal_data_matching.rb +120 -0
- data/app/models/concerns/spree/preference_schema.rb +120 -19
- data/app/models/concerns/spree/prefixed_id.rb +25 -3
- data/app/models/concerns/spree/presentation_translatable.rb +4 -37
- data/app/models/concerns/spree/product_scopes.rb +51 -191
- data/app/models/concerns/spree/provider_failure_policy.rb +44 -0
- data/app/models/concerns/spree/publishable.rb +7 -7
- data/app/models/concerns/spree/purchase/addresses.rb +258 -0
- data/app/models/concerns/spree/purchase/channel.rb +19 -0
- data/app/models/concerns/spree/purchase/checkout_steps.rb +68 -0
- data/app/models/concerns/spree/purchase/company.rb +96 -0
- data/app/models/concerns/spree/purchase/currency.rb +29 -0
- data/app/models/concerns/spree/purchase/digital_items.rb +60 -0
- data/app/models/concerns/spree/purchase/freight.rb +52 -0
- data/app/models/concerns/spree/purchase/gift_cards.rb +70 -0
- data/app/models/concerns/spree/purchase/lifecycle.rb +53 -0
- data/app/models/concerns/spree/purchase/line_item_currencies.rb +38 -0
- data/app/models/concerns/spree/purchase/line_item_lookup.rb +25 -0
- data/app/models/concerns/spree/purchase/locale.rb +30 -0
- data/app/models/concerns/spree/purchase/market.rb +29 -0
- data/app/models/concerns/spree/purchase/payment_processing.rb +93 -0
- data/app/models/concerns/spree/purchase/purchase_order.rb +94 -0
- data/app/models/concerns/spree/purchase/quantity_rules.rb +136 -0
- data/app/models/concerns/spree/purchase/store_credits.rb +100 -0
- data/app/models/concerns/spree/purchase/taxation.rb +146 -0
- data/app/models/concerns/spree/purchase/totals.rb +116 -0
- data/app/models/concerns/spree/purchase/validations.rb +45 -0
- data/app/models/concerns/spree/receivable.rb +103 -0
- data/app/models/concerns/spree/receivable_item.rb +78 -0
- data/app/models/concerns/spree/refund_methods.rb +19 -0
- data/app/models/concerns/spree/sanitizable_rich_text.rb +109 -0
- data/app/models/concerns/spree/search_indexable.rb +5 -2
- data/app/models/concerns/spree/single_store_resource.rb +3 -1
- data/app/models/concerns/spree/store_data_sources.rb +75 -0
- data/app/models/concerns/spree/store_preferences.rb +49 -0
- data/app/models/concerns/spree/stores/markets.rb +75 -28
- data/app/models/concerns/spree/stores/setup.rb +10 -0
- data/app/models/concerns/spree/translatable_resource.rb +25 -6
- data/app/models/concerns/spree/typed_adjustment_line.rb +55 -0
- data/app/models/concerns/spree/user_address.rb +13 -3
- data/app/models/concerns/spree/user_management.rb +18 -6
- data/app/models/concerns/spree/user_methods.rb +5 -330
- data/app/models/concerns/spree/user_payment_source.rb +1 -1
- data/app/models/concerns/spree/user_roles.rb +18 -11
- data/app/models/concerns/spree/validates_store_uniqueness.rb +53 -0
- data/app/models/concerns/spree/vat_price_calculation.rb +58 -6
- data/app/models/concerns/spree/webhook_payload_redaction.rb +1 -1
- data/app/models/spree/ability.rb +147 -43
- data/app/models/spree/address.rb +387 -118
- data/app/models/spree/adjusters/base.rb +26 -0
- data/app/models/spree/adjusters/largest_remainder.rb +24 -0
- data/app/models/spree/adjusters/promotion.rb +253 -0
- data/app/models/spree/admin_user.rb +26 -0
- data/app/models/spree/allowed_origin.rb +1 -1
- data/app/models/spree/api_key.rb +34 -31
- data/app/models/spree/asset.rb +14 -211
- data/app/models/spree/authentication/strategies/base_strategy.rb +54 -3
- data/app/models/spree/authentication/strategies/email_password_strategy.rb +11 -3
- data/app/models/spree/authentication/strategies/oidc_strategy.rb +330 -0
- data/app/models/spree/authentication/strategy_registry.rb +83 -0
- data/app/models/spree/base.rb +83 -12
- data/app/models/spree/base_analytics_event_handler.rb +1 -1
- data/app/models/spree/calculator/shipping/digital_delivery.rb +5 -2
- data/app/models/spree/calculator/shipping/flat_rate.rb +10 -5
- data/app/models/spree/calculator/shipping/flexi_rate.rb +6 -0
- data/app/models/spree/calculator/shipping/per_item.rb +8 -3
- data/app/models/spree/calculator/shipping/price_sack.rb +6 -0
- data/app/models/spree/calculator/tiered_flat_rate.rb +5 -1
- data/app/models/spree/calculator.rb +10 -0
- data/app/models/spree/cart.rb +285 -0
- data/app/models/spree/carts/item_warning.rb +28 -0
- data/app/models/spree/carts/resolved_item.rb +37 -0
- data/app/models/spree/catalog.rb +503 -0
- data/app/models/spree/catalog_assignment.rb +41 -0
- data/app/models/spree/catalog_order_minimum.rb +26 -0
- data/app/models/spree/catalog_price.rb +100 -0
- data/app/models/spree/catalog_price_tier.rb +36 -0
- data/app/models/spree/catalog_product.rb +23 -0
- data/app/models/spree/catalog_quantity_rule.rb +46 -0
- data/app/models/spree/catalogs/product_term.rb +43 -0
- data/app/models/spree/category.rb +430 -12
- data/app/models/spree/channel/gating.rb +1 -2
- data/app/models/spree/channel.rb +38 -4
- data/app/models/spree/channel_stock_location.rb +8 -0
- data/app/models/spree/claim.rb +69 -0
- data/app/models/spree/claim_line_item.rb +46 -0
- data/app/models/spree/claim_reason.rb +24 -0
- data/app/models/spree/classification.rb +7 -49
- data/app/models/spree/collection.rb +269 -0
- data/app/models/spree/collection_rule.rb +58 -0
- data/app/models/spree/collection_rules/available_on.rb +21 -0
- data/app/models/spree/collection_rules/sale.rb +18 -0
- data/app/models/spree/collection_rules/tag.rb +21 -0
- data/app/models/spree/commission_line.rb +85 -0
- data/app/models/spree/commission_rate.rb +370 -0
- data/app/models/spree/commission_rate_value.rb +47 -0
- data/app/models/spree/commission_rule.rb +77 -0
- data/app/models/spree/commission_rule_product.rb +19 -0
- data/app/models/spree/commission_rules/category_rule.rb +33 -0
- data/app/models/spree/commission_rules/item_total_rule.rb +31 -0
- data/app/models/spree/commission_rules/product_rule.rb +55 -0
- data/app/models/spree/commission_rules/seller_rule.rb +33 -0
- data/app/models/spree/commission_tax.rb +51 -0
- data/app/models/spree/commissions/context.rb +71 -0
- data/app/models/spree/company.rb +347 -0
- data/app/models/spree/company_invitation.rb +81 -0
- data/app/models/spree/company_membership.rb +25 -0
- data/app/models/spree/consent_record.rb +125 -0
- data/app/models/spree/country.rb +128 -52
- data/app/models/spree/coupon_code.rb +18 -5
- data/app/models/spree/credit_card.rb +10 -9
- data/app/models/spree/current.rb +152 -18
- data/app/models/spree/custom_field.rb +160 -7
- data/app/models/spree/custom_field_definition/search_capabilities.rb +98 -0
- data/app/models/spree/custom_field_definition.rb +219 -5
- data/app/models/spree/custom_fields/boolean.rb +15 -0
- data/app/models/spree/custom_fields/json.rb +38 -0
- data/app/models/spree/custom_fields/long_text.rb +11 -0
- data/app/models/spree/custom_fields/number.rb +23 -0
- data/app/models/spree/custom_fields/rich_text.rb +23 -0
- data/app/models/spree/custom_fields/short_text.rb +15 -0
- data/app/models/spree/customer.rb +34 -0
- data/app/models/spree/customer_group.rb +12 -12
- data/app/models/spree/customer_group_user.rb +6 -4
- data/app/models/spree/data_feed.rb +1 -1
- data/app/models/spree/data_request.rb +98 -0
- data/app/models/spree/delivery.rb +169 -0
- data/app/models/spree/delivery_method.rb +566 -0
- data/app/models/spree/delivery_method_rule.rb +55 -0
- data/app/models/spree/delivery_method_rule_product.rb +8 -0
- data/app/models/spree/delivery_method_rules/channel_rule.rb +41 -0
- data/app/models/spree/delivery_method_rules/company_rule.rb +24 -0
- data/app/models/spree/delivery_method_rules/excluded_products_rule.rb +48 -0
- data/app/models/spree/delivery_method_rules/item_total_rule.rb +19 -0
- data/app/models/spree/delivery_method_rules/volume_rule.rb +35 -0
- data/app/models/spree/delivery_method_rules/weight_rule.rb +19 -0
- data/app/models/spree/delivery_method_service.rb +24 -0
- data/app/models/spree/delivery_method_stock_location.rb +11 -0
- data/app/models/spree/delivery_origin_group.rb +73 -0
- data/app/models/spree/delivery_origin_group_location.rb +9 -0
- data/app/models/spree/delivery_profile.rb +141 -0
- data/app/models/spree/delivery_profiles/digital.rb +20 -0
- data/app/models/spree/delivery_profiles/shipping.rb +12 -0
- data/app/models/spree/delivery_rate.rb +164 -0
- data/app/models/spree/delivery_rate_provider/base.rb +120 -0
- data/app/models/spree/delivery_rate_provider/estimate.rb +44 -0
- data/app/models/spree/delivery_rate_provider/freight.rb +41 -0
- data/app/models/spree/delivery_rate_provider/internal.rb +28 -0
- data/app/models/spree/delivery_rate_provider/service_catalog.rb +48 -0
- data/app/models/spree/delivery_zone.rb +64 -0
- data/app/models/spree/delivery_zone_member.rb +98 -0
- data/app/models/spree/digital.rb +12 -16
- data/app/models/spree/digital_asset.rb +144 -0
- data/app/models/spree/digital_asset_provider/base.rb +95 -0
- data/app/models/spree/digital_asset_provider/file.rb +20 -0
- data/app/models/spree/digital_delivery.rb +28 -0
- data/app/models/spree/digital_link.rb +31 -11
- data/app/models/spree/discount.rb +51 -0
- data/app/models/spree/event.rb +6 -6
- data/app/models/spree/exchange.rb +50 -44
- data/app/models/spree/exchange_line_item.rb +52 -0
- data/app/models/spree/export.rb +128 -21
- data/app/models/spree/exports/customers.rb +2 -2
- data/app/models/spree/exports/gift_cards.rb +2 -2
- data/app/models/spree/exports/newsletter_subscribers.rb +2 -2
- data/app/models/spree/exports/orders.rb +35 -5
- data/app/models/spree/exports/price_list_prices.rb +107 -0
- data/app/models/spree/exports/products.rb +4 -4
- data/app/models/spree/exports/purchase_orders.rb +39 -0
- data/app/models/spree/exports/report.rb +95 -0
- data/app/models/spree/external_reference.rb +77 -0
- data/app/models/spree/external_video.rb +117 -0
- data/app/models/spree/fee.rb +40 -0
- data/app/models/spree/freight_summary/line.rb +257 -0
- data/app/models/spree/freight_summary.rb +180 -0
- data/app/models/spree/fulfillment/custom_events.rb +96 -0
- data/app/models/spree/fulfillment.rb +973 -0
- data/app/models/spree/fulfillment_changer.rb +170 -0
- data/app/models/spree/fulfillment_item.rb +148 -0
- data/app/models/spree/fulfillment_provider/base.rb +130 -0
- data/app/models/spree/fulfillment_provider/digital.rb +44 -0
- data/app/models/spree/fulfillment_provider/manual.rb +15 -0
- data/app/models/spree/fulfillment_provider/pickup.rb +38 -0
- data/app/models/spree/fulfillment_provider/pickup_point.rb +24 -0
- data/app/models/spree/fulfilment_changer.rb +3 -164
- data/app/models/spree/gateway/bogus.rb +5 -4
- data/app/models/spree/gateway/custom_payment_source_method.rb +5 -5
- data/app/models/spree/gateway.rb +2 -2
- data/app/models/spree/gateway_customer.rb +12 -4
- data/app/models/spree/gift_card.rb +140 -48
- data/app/models/spree/gift_card_batch.rb +2 -2
- data/app/models/spree/import.rb +136 -98
- data/app/models/spree/import_mapping.rb +1 -1
- data/app/models/spree/import_row.rb +35 -31
- data/app/models/spree/import_schemas/price_list_prices.rb +13 -0
- data/app/models/spree/import_schemas/products.rb +8 -1
- data/app/models/spree/import_schemas/purchase_orders.rb +19 -0
- data/app/models/spree/imports/price_list_prices.rb +72 -0
- data/app/models/spree/imports/purchase_orders.rb +28 -0
- data/app/models/spree/integration.rb +128 -5
- data/app/models/spree/inventory_provider/base.rb +30 -0
- data/app/models/spree/inventory_provider/internal.rb +22 -0
- data/app/models/spree/inventory_unit.rb +3 -139
- data/app/models/spree/invitation.rb +53 -47
- data/app/models/spree/label_purchase.rb +29 -0
- data/app/models/spree/line_item.rb +240 -106
- data/app/models/spree/market.rb +106 -15
- data/app/models/spree/market_country.rb +10 -5
- data/app/models/spree/media.rb +497 -0
- data/app/models/spree/media_usage_reference.rb +27 -0
- data/app/models/spree/metafield.rb +14 -102
- data/app/models/spree/metafield_definition.rb +11 -128
- data/app/models/spree/metafields.rb +32 -0
- data/app/models/spree/newsletter_subscriber.rb +10 -9
- data/app/models/spree/number_generators/base.rb +56 -0
- data/app/models/spree/number_generators/random.rb +23 -0
- data/app/models/spree/number_generators/sequential.rb +88 -0
- data/app/models/spree/number_sequence.rb +86 -0
- data/app/models/spree/option_type.rb +18 -32
- data/app/models/spree/option_type_product_type.rb +8 -0
- data/app/models/spree/option_value.rb +19 -13
- data/app/models/spree/option_value_variant.rb +0 -1
- data/app/models/spree/order.rb +681 -576
- data/app/models/spree/order_cancellation_reason.rb +25 -0
- data/app/models/spree/order_group.rb +244 -0
- data/app/models/spree/order_inventory.rb +42 -33
- data/app/models/spree/order_merger.rb +11 -6
- data/app/models/spree/order_promotion.rb +32 -6
- data/app/models/spree/order_routing/has_strategy_preference.rb +1 -2
- data/app/models/spree/order_routing/rules/minimize_splits.rb +6 -6
- data/app/models/spree/order_routing/strategy/rules.rb +12 -8
- data/app/models/spree/order_routing_rule.rb +5 -15
- data/app/models/spree/order_updater.rb +131 -163
- data/app/models/spree/package_type.rb +191 -0
- data/app/models/spree/payment/custom_events.rb +52 -5
- data/app/models/spree/payment/gateway_options.rb +20 -5
- data/app/models/spree/payment/processing.rb +95 -116
- data/app/models/spree/payment.rb +299 -123
- data/app/models/spree/payment_method/check.rb +4 -3
- data/app/models/spree/payment_method/session_instrumentation.rb +34 -0
- data/app/models/spree/payment_method/store_credit.rb +4 -2
- data/app/models/spree/payment_method.rb +106 -9
- data/app/models/spree/payment_session.rb +150 -53
- data/app/models/spree/payment_setup_session.rb +4 -37
- data/app/models/spree/payment_source.rb +5 -4
- data/app/models/spree/payment_split.rb +90 -0
- data/app/models/spree/payout_provider/base.rb +218 -0
- data/app/models/spree/payout_provider/system.rb +36 -0
- data/app/models/spree/permission_sets.rb +17 -0
- data/app/models/spree/pickup_point_option.rb +28 -0
- data/app/models/spree/pickup_point_provider/base.rb +24 -0
- data/app/models/spree/policy.rb +12 -11
- data/app/models/spree/price.rb +91 -5
- data/app/models/spree/price_adjustment_tier.rb +63 -0
- data/app/models/spree/price_history.rb +1 -1
- data/app/models/spree/price_list.rb +266 -142
- data/app/models/spree/price_rule.rb +51 -7
- data/app/models/spree/price_rules/channel_rule.rb +3 -0
- data/app/models/spree/price_rules/customer_group_rule.rb +10 -1
- data/app/models/spree/price_rules/market_rule.rb +6 -0
- data/app/models/spree/price_rules/user_rule.rb +12 -3
- data/app/models/spree/price_rules/volume_rule.rb +6 -0
- data/app/models/spree/price_rules/zone_rule.rb +5 -13
- data/app/models/spree/pricing_provider/base.rb +51 -0
- data/app/models/spree/pricing_provider/internal.rb +277 -0
- data/app/models/spree/pricing_provider.rb +28 -0
- data/app/models/spree/product.rb +528 -544
- data/app/models/spree/product_category.rb +65 -0
- data/app/models/spree/product_collection.rb +20 -0
- data/app/models/spree/product_option_type.rb +0 -1
- data/app/models/spree/product_promotion_rule.rb +0 -1
- data/app/models/spree/product_publication.rb +0 -1
- data/app/models/spree/product_submission.rb +72 -0
- data/app/models/spree/product_type.rb +116 -0
- data/app/models/spree/product_type_category.rb +8 -0
- data/app/models/spree/product_type_custom_field_definition.rb +39 -0
- data/app/models/spree/promotion/actions/create_adjustment.rb +9 -7
- data/app/models/spree/promotion/actions/create_item_adjustments.rb +11 -16
- data/app/models/spree/promotion/actions/create_line_items.rb +19 -8
- data/app/models/spree/promotion/actions/free_shipping.rb +12 -18
- data/app/models/spree/promotion/rules/category.rb +181 -0
- data/app/models/spree/promotion/rules/channel.rb +3 -3
- data/app/models/spree/promotion/rules/country.rb +43 -17
- data/app/models/spree/promotion/rules/currency.rb +2 -2
- data/app/models/spree/promotion/rules/customer_group.rb +13 -5
- data/app/models/spree/promotion/rules/first_order.rb +3 -3
- data/app/models/spree/promotion/rules/item_total.rb +2 -2
- data/app/models/spree/promotion/rules/market.rb +3 -3
- data/app/models/spree/promotion/rules/one_use_per_user.rb +4 -4
- data/app/models/spree/promotion/rules/option_value.rb +34 -11
- data/app/models/spree/promotion/rules/product.rb +3 -5
- data/app/models/spree/promotion/rules/taxon.rb +10 -131
- data/app/models/spree/promotion/rules/user.rb +14 -22
- data/app/models/spree/promotion/rules/user_logged_in.rb +3 -3
- data/app/models/spree/promotion.rb +59 -21
- data/app/models/spree/promotion_action.rb +52 -11
- data/app/models/spree/promotion_action_line_item.rb +1 -1
- data/app/models/spree/promotion_handler/coupon.rb +44 -16
- data/app/models/spree/promotion_handler/free_shipping.rb +1 -1
- data/app/models/spree/promotion_handler/promotion_duplicator.rb +1 -1
- data/app/models/spree/promotion_rule.rb +2 -9
- data/app/models/spree/promotion_rule_category.rb +22 -0
- data/app/models/spree/promotion_rule_taxon.rb +7 -6
- data/app/models/spree/promotion_rule_user.rb +2 -2
- data/app/models/spree/prototype.rb +3 -13
- data/app/models/spree/purchase_order.rb +95 -0
- data/app/models/spree/purchase_order_item.rb +40 -0
- data/app/models/spree/quantity_rule.rb +114 -0
- data/app/models/spree/refresh_token.rb +20 -2
- data/app/models/spree/refund.rb +96 -42
- data/app/models/spree/refund_reason.rb +32 -11
- data/app/models/spree/return.rb +151 -0
- data/app/models/spree/return_authorization_reason.rb +11 -6
- data/app/models/spree/return_line_item.rb +42 -0
- data/app/models/spree/return_reason.rb +26 -0
- data/app/models/spree/rich_text_sanitizer.rb +99 -0
- data/app/models/spree/role.rb +179 -4
- data/app/models/spree/role_user.rb +5 -21
- data/app/models/spree/saved_report.rb +56 -0
- data/app/models/spree/search_provider/base.rb +8 -2
- data/app/models/spree/search_provider/database.rb +73 -22
- data/app/models/spree/search_provider.rb +29 -0
- data/app/models/spree/seller.rb +475 -0
- data/app/models/spree/seller_balance.rb +86 -0
- data/app/models/spree/seller_payout.rb +116 -0
- data/app/models/spree/seller_requirement.rb +274 -0
- data/app/models/spree/seller_requirement_custom_field.rb +38 -0
- data/app/models/spree/seller_requirement_status.rb +144 -0
- data/app/models/spree/seller_requirement_submission.rb +91 -0
- data/app/models/spree/seller_requirements/accept_terms.rb +104 -0
- data/app/models/spree/seller_requirements/attestation.rb +22 -0
- data/app/models/spree/seller_requirements/billing_address.rb +13 -0
- data/app/models/spree/seller_requirements/complete_profile.rb +26 -0
- data/app/models/spree/seller_requirements/delivery_method.rb +20 -0
- data/app/models/spree/seller_requirements/document.rb +62 -0
- data/app/models/spree/seller_requirements/minimum_products.rb +20 -0
- data/app/models/spree/seller_requirements/operator_review.rb +23 -0
- data/app/models/spree/seller_requirements/package_type.rb +40 -0
- data/app/models/spree/seller_requirements/payout_account.rb +55 -0
- data/app/models/spree/seller_requirements/policy.rb +43 -0
- data/app/models/spree/seller_requirements/required_custom_fields.rb +56 -0
- data/app/models/spree/seller_requirements/returns_address.rb +19 -0
- data/app/models/spree/seller_transfer.rb +166 -0
- data/app/models/spree/setup_tasks.rb +3 -6
- data/app/models/spree/shipment.rb +3 -560
- data/app/models/spree/shipping_calculator.rb +7 -0
- data/app/models/spree/shipping_document.rb +32 -0
- data/app/models/spree/shipping_label.rb +146 -0
- data/app/models/spree/shipping_method.rb +3 -146
- data/app/models/spree/shipping_rate.rb +3 -97
- data/app/models/spree/state.rb +57 -23
- data/app/models/spree/stock/availability_validator.rb +1 -1
- data/app/models/spree/stock/content_item.rb +1 -0
- data/app/models/spree/stock/coordinator.rb +69 -9
- data/app/models/spree/stock/estimator.rb +198 -33
- data/app/models/spree/stock/inventory_unit_builder.rb +6 -1
- data/app/models/spree/stock/package.rb +145 -14
- data/app/models/spree/stock/packer.rb +20 -3
- data/app/models/spree/stock/prioritizer.rb +27 -4
- data/app/models/spree/stock/quantifier.rb +63 -38
- data/app/models/spree/stock/splitter/base.rb +3 -1
- data/app/models/spree/stock/splitter/delivery_profile.rb +41 -0
- data/app/models/spree/stock_item.rb +3 -147
- data/app/models/spree/stock_level/custom_events.rb +48 -0
- data/app/models/spree/stock_level.rb +305 -0
- data/app/models/spree/stock_location.rb +165 -87
- data/app/models/spree/stock_movement/custom_events.rb +1 -1
- data/app/models/spree/stock_movement.rb +166 -22
- data/app/models/spree/stock_receipt.rb +61 -0
- data/app/models/spree/stock_receipt_item.rb +35 -0
- data/app/models/spree/stock_reservation.rb +114 -11
- data/app/models/spree/stock_transfer.rb +84 -59
- data/app/models/spree/stock_transfer_item.rb +25 -0
- data/app/models/spree/store.rb +431 -107
- data/app/models/spree/store_credit.rb +88 -21
- data/app/models/spree/store_credit_category.rb +21 -28
- data/app/models/spree/store_credit_event.rb +1 -1
- data/app/models/spree/store_credit_type.rb +10 -2
- data/app/models/spree/store_payment_method.rb +0 -1
- data/app/models/spree/store_product.rb +2 -2
- data/app/models/spree/store_promotion.rb +0 -1
- data/app/models/spree/storefront/access_denied.rb +22 -0
- data/app/models/spree/storefront/access_policy.rb +180 -0
- data/app/models/spree/subscriber.rb +6 -6
- data/app/models/spree/supplier.rb +76 -0
- data/app/models/spree/tax_category.rb +15 -5
- data/app/models/spree/tax_exemption/item_override.rb +22 -0
- data/app/models/spree/tax_exemption.rb +81 -0
- data/app/models/spree/tax_exemption_certificate.rb +95 -0
- data/app/models/spree/tax_identifier.rb +209 -0
- data/app/models/spree/tax_identifiers/validation_result.rb +41 -0
- data/app/models/spree/tax_identifiers/validator/base.rb +53 -0
- data/app/models/spree/tax_identifiers/validator/eu_vat.rb +76 -0
- data/app/models/spree/tax_line.rb +79 -0
- data/app/models/spree/tax_provider/base.rb +150 -0
- data/app/models/spree/tax_provider/internal.rb +227 -0
- data/app/models/spree/tax_rate.rb +63 -100
- data/app/models/spree/taxon.rb +13 -514
- data/app/models/spree/taxon_rule.rb +8 -9
- data/app/models/spree/taxonomy.rb +8 -42
- data/app/models/spree/user_identity.rb +2 -2
- data/app/models/spree/variant.rb +629 -150
- data/app/models/spree/variant_media.rb +6 -7
- data/app/models/spree/webhook_endpoint.rb +2 -1
- data/app/models/spree/wished_item.rb +3 -31
- data/app/models/spree/wishlist.rb +17 -10
- data/app/models/spree/wishlist_item/custom_events.rb +42 -0
- data/app/models/spree/wishlist_item.rb +37 -0
- data/app/models/spree/zone.rb +24 -182
- data/app/models/spree/zone_member.rb +5 -8
- data/app/presenters/spree/csv/custom_fields_helper.rb +25 -0
- data/app/presenters/spree/csv/customer_presenter.rb +7 -6
- data/app/presenters/spree/csv/gift_card_presenter.rb +9 -8
- data/app/presenters/spree/csv/newsletter_subscriber_presenter.rb +7 -6
- data/app/presenters/spree/csv/order_line_item_presenter.rb +53 -21
- data/app/presenters/spree/csv/price_list_price_presenter.rb +41 -0
- data/app/presenters/spree/csv/product_variant_presenter.rb +22 -21
- data/app/presenters/spree/csv/purchase_order_item_presenter.rb +50 -0
- data/app/presenters/spree/data_feeds/google_presenter.rb +24 -10
- data/app/presenters/spree/filters/options_presenter.rb +2 -2
- data/app/services/spree/addresses/create.rb +70 -27
- data/app/services/spree/addresses/helper.rb +17 -54
- data/app/services/spree/addresses/update.rb +53 -31
- data/app/services/spree/carts/associate.rb +46 -0
- data/app/services/spree/carts/check_availability.rb +72 -0
- data/app/services/spree/carts/create.rb +7 -1
- data/app/services/spree/carts/destroy.rb +71 -0
- data/app/services/spree/carts/empty.rb +42 -0
- data/app/services/spree/carts/partition_by_seller.rb +71 -0
- data/app/services/spree/carts/price_items.rb +119 -0
- data/app/services/spree/carts/remove_item.rb +42 -0
- data/app/services/spree/carts/remove_line_item.rb +42 -0
- data/app/services/spree/carts/remove_out_of_stock_items.rb +104 -0
- data/app/services/spree/carts/set_quantity.rb +39 -0
- data/app/services/spree/carts/split_by_seller.rb +475 -0
- data/app/services/spree/carts/update.rb +157 -51
- data/app/services/spree/catalogs/resolve_prices.rb +192 -0
- data/app/services/spree/catalogs/resolve_quantity_rules.rb +115 -0
- data/app/services/spree/catalogs/set_assignments.rb +59 -0
- data/app/services/spree/catalogs/set_order_minimums.rb +44 -0
- data/app/services/spree/catalogs/set_product_terms.rb +83 -0
- data/app/services/spree/categories/add_products.rb +51 -0
- data/app/services/spree/categories/remove_products.rb +72 -0
- data/app/services/spree/checkout/add_store_credit.rb +11 -79
- data/app/services/spree/checkout/advance.rb +38 -38
- data/app/services/spree/checkout/remove_store_credit.rb +7 -12
- data/app/services/spree/collections/add_products.rb +42 -0
- data/app/services/spree/collections/regenerate_products.rb +67 -0
- data/app/services/spree/collections/remove_products.rb +65 -0
- data/app/services/spree/commissions/calculate_line.rb +132 -0
- data/app/services/spree/commissions/commission_order.rb +185 -0
- data/app/services/spree/commissions/resolve_rate.rb +114 -0
- data/app/services/spree/commissions/resolve_tax_rate.rb +78 -0
- data/app/services/spree/companies/add_member.rb +38 -0
- data/app/services/spree/company_invitations/accept.rb +60 -0
- data/app/services/spree/coupon_codes/coupon_codes_handler.rb +14 -2
- data/app/services/spree/customers/data_export.rb +372 -0
- data/app/services/spree/data_requests/create.rb +77 -0
- data/app/services/spree/deliveries/create.rb +56 -0
- data/app/services/spree/deliveries/destroy.rb +39 -0
- data/app/services/spree/deliveries/upsert_primary.rb +43 -0
- data/app/services/spree/fulfillments/recalculate_delivery.rb +62 -0
- data/app/services/spree/fulfillments/stand_down_provider.rb +47 -0
- data/app/services/spree/imports/row_processors/customer.rb +8 -8
- data/app/services/spree/imports/row_processors/price_list_price.rb +164 -0
- data/app/services/spree/imports/row_processors/product_variant.rb +193 -57
- data/app/services/spree/imports/row_processors/purchase_order.rb +157 -0
- data/app/services/spree/media/destroy.rb +88 -0
- data/app/services/spree/media/usage.rb +175 -0
- data/app/services/spree/newsletter/link_user.rb +4 -3
- data/app/services/spree/newsletter/subscribe.rb +3 -3
- data/app/services/spree/newsletter/verify.rb +6 -2
- data/app/services/spree/order_groups/allocate_payments.rb +101 -0
- data/app/services/spree/orders/approve.rb +11 -24
- data/app/services/spree/orders/build_fulfillments.rb +29 -0
- data/app/services/spree/orders/create.rb +38 -17
- data/app/services/spree/orders/create_from_cart.rb +88 -0
- data/app/services/spree/orders/create_user_account.rb +14 -67
- data/app/services/spree/orders/discounts/create.rb +84 -0
- data/app/services/spree/orders/discounts/destroy.rb +25 -0
- data/app/services/spree/orders/discounts/update.rb +29 -0
- data/app/services/spree/orders/fees/create.rb +28 -0
- data/app/services/spree/orders/fees/destroy.rb +22 -0
- data/app/services/spree/orders/fees/update.rb +25 -0
- data/app/services/spree/orders/remove_item.rb +13 -0
- data/app/services/spree/orders/remove_line_item.rb +13 -0
- data/app/services/spree/orders/update.rb +56 -11
- data/app/services/spree/orders/update_item.rb +105 -0
- data/app/services/spree/orders/update_statuses.rb +109 -0
- data/app/services/spree/payments/create.rb +31 -5
- data/app/services/spree/prices/bulk_upsert.rb +156 -30
- data/app/services/spree/product_submissions/close.rb +46 -0
- data/app/services/spree/product_types/apply_to_products.rb +167 -0
- data/app/services/spree/products/auto_match_collections.rb +75 -0
- data/app/services/spree/products/auto_match_taxons.rb +7 -54
- data/app/services/spree/products/duplicator.rb +16 -22
- data/app/services/spree/products/for_context.rb +54 -0
- data/app/services/spree/products/select_buy_box.rb +98 -0
- data/app/services/spree/purchases/amount_due_at_checkout.rb +33 -0
- data/app/services/spree/returns/eligibility_validator.rb +53 -0
- data/app/services/spree/sample_data/helper.rb +3 -3
- data/app/services/spree/sample_data/import_builder.rb +8 -4
- data/app/services/spree/sample_data/import_runner.rb +7 -4
- data/app/services/spree/sample_data/loader.rb +15 -6
- data/app/services/spree/search_provider/custom_field_schema.rb +153 -0
- data/app/services/spree/seeds/admin_user.rb +72 -12
- data/app/services/spree/seeds/all.rb +24 -13
- data/app/services/spree/seeds/commission_rates.rb +53 -0
- data/app/services/spree/seeds/digital_delivery.rb +18 -8
- data/app/services/spree/seeds/product_types.rb +23 -0
- data/app/services/spree/seeds/returns_environment.rb +44 -16
- data/app/services/spree/seeds/roles.rb +6 -1
- data/app/services/spree/seeds/saved_reports.rb +107 -0
- data/app/services/spree/seeds/seller_requirements.rb +19 -0
- data/app/services/spree/seeds/stores.rb +1 -1
- data/app/services/spree/seeds/tax_categories.rb +9 -2
- data/app/services/spree/sellers/requirements.rb +129 -0
- data/app/services/spree/shipments/update.rb +4 -33
- data/app/services/spree/shipping_labels/confirm_refund.rb +47 -0
- data/app/services/spree/shipping_labels/store_file.rb +68 -0
- data/app/services/spree/stock_levels/bulk_upsert.rb +67 -0
- data/app/services/spree/stock_levels/correct.rb +69 -0
- data/app/services/spree/stock_levels/recount.rb +103 -0
- data/app/services/spree/stock_locations/stock_items/create.rb +8 -13
- data/app/services/spree/stock_locations/stock_levels/create.rb +25 -0
- data/app/services/spree/stock_reservations/extend.rb +9 -5
- data/app/services/spree/stock_reservations/release.rb +4 -3
- data/app/services/spree/stock_reservations/reserve.rb +43 -32
- data/app/services/spree/store_credits/apply.rb +93 -0
- data/app/services/spree/store_credits/remove.rb +17 -0
- data/app/services/spree/stores/provision_defaults.rb +269 -0
- data/app/services/spree/tax/resolve_exemptions.rb +44 -0
- data/app/services/spree/tax/unusable_exemption_error.rb +8 -0
- data/app/services/spree/tax_identifiers/validate.rb +77 -0
- data/app/services/spree/taxons/add_products.rb +6 -39
- data/app/services/spree/taxons/regenerate_products.rb +8 -53
- data/app/services/spree/taxons/remove_products.rb +6 -60
- data/app/services/spree/variants/remove_line_items.rb +6 -1
- data/app/subscribers/spree/event_log_subscriber.rb +1 -1
- data/app/subscribers/spree/order_commission_subscriber.rb +23 -0
- data/app/subscribers/spree/order_placed_subscriber.rb +58 -0
- data/app/subscribers/spree/order_status_subscriber.rb +82 -0
- data/app/subscribers/spree/payment_split_subscriber.rb +71 -0
- data/app/subscribers/spree/product_metrics_subscriber.rb +2 -2
- data/app/subscribers/spree/seller_onboarding_subscriber.rb +32 -0
- data/app/subscribers/spree/seller_transfer_reversal_subscriber.rb +26 -0
- data/app/subscribers/spree/seller_transfer_subscriber.rb +26 -0
- data/app/subscribers/spree/seller_user_email_subscriber.rb +27 -0
- data/app/subscribers/spree/tax_identifier_validation_subscriber.rb +26 -0
- data/app/validators/spree/addresses/phone_validator.rb +2 -2
- data/app/validators/spree/attachment_content_type_validator.rb +183 -0
- data/app/validators/spree/password_length_validator.rb +23 -0
- data/app/views/spree/seller_user_mailer/password_reset_email.html.erb +8 -0
- data/app/views/spree/shared/_purchased_items_styles.html.erb +7 -0
- data/app/workflows/spree/carts/add_item.rb +234 -0
- data/app/workflows/spree/carts/complete.rb +516 -0
- data/app/workflows/spree/carts/merge.rb +90 -0
- data/app/workflows/spree/carts/recalculate.rb +54 -0
- data/app/workflows/spree/carts/recalculate_totals.rb +233 -0
- data/app/workflows/spree/carts/upsert_items.rb +368 -0
- data/app/workflows/spree/catalogs/activate.rb +51 -0
- data/app/workflows/spree/catalogs/create.rb +83 -0
- data/app/workflows/spree/catalogs/deactivate.rb +35 -0
- data/app/workflows/spree/catalogs/set_price_list.rb +130 -0
- data/app/workflows/spree/catalogs/update.rb +85 -0
- data/app/workflows/spree/claims/approve.rb +38 -0
- data/app/workflows/spree/claims/cancel.rb +37 -0
- data/app/workflows/spree/claims/create.rb +82 -0
- data/app/workflows/spree/claims/deny.rb +35 -0
- data/app/workflows/spree/claims/resolve.rb +166 -0
- data/app/workflows/spree/customers/anonymize.rb +502 -0
- data/app/workflows/spree/customers/create.rb +247 -0
- data/app/workflows/spree/data_requests/fulfill.rb +165 -0
- data/app/workflows/spree/deliveries/update_tracking.rb +96 -0
- data/app/workflows/spree/exchanges/approve.rb +38 -0
- data/app/workflows/spree/exchanges/cancel.rb +40 -0
- data/app/workflows/spree/exchanges/create.rb +90 -0
- data/app/workflows/spree/exchanges/fulfill.rb +146 -0
- data/app/workflows/spree/exchanges/receive.rb +86 -0
- data/app/workflows/spree/fulfillments/cancel.rb +87 -0
- data/app/workflows/spree/fulfillments/create.rb +346 -0
- data/app/workflows/spree/fulfillments/fulfill.rb +354 -0
- data/app/workflows/spree/fulfillments/mark_delivered.rb +67 -0
- data/app/workflows/spree/fulfillments/purchase_label.rb +40 -0
- data/app/workflows/spree/fulfillments/update.rb +123 -0
- data/app/workflows/spree/gift_cards/apply.rb +235 -0
- data/app/workflows/spree/gift_cards/cancel.rb +43 -0
- data/app/workflows/spree/gift_cards/redeem.rb +59 -0
- data/app/workflows/spree/gift_cards/remove.rb +78 -0
- data/app/workflows/spree/imports/complete.rb +45 -0
- data/app/workflows/spree/imports/complete_mapping.rb +50 -0
- data/app/workflows/spree/imports/retry_failed_rows.rb +46 -0
- data/app/workflows/spree/imports/start_mapping.rb +48 -0
- data/app/workflows/spree/imports/start_processing.rb +36 -0
- data/app/workflows/spree/invitations/accept.rb +50 -0
- data/app/workflows/spree/orders/add_item.rb +12 -0
- data/app/workflows/spree/orders/cancel.rb +261 -0
- data/app/workflows/spree/orders/complete.rb +169 -0
- data/app/workflows/spree/orders/recalculate.rb +11 -0
- data/app/workflows/spree/orders/recalculate_totals.rb +12 -0
- data/app/workflows/spree/orders/upsert_items.rb +28 -0
- data/app/workflows/spree/payment_sessions/complete.rb +44 -0
- data/app/workflows/spree/payments/capture.rb +109 -0
- data/app/workflows/spree/payments/handle_webhook.rb +100 -0
- data/app/workflows/spree/payments/process.rb +73 -0
- data/app/workflows/spree/payments/void.rb +72 -0
- data/app/workflows/spree/price_lists/activate.rb +49 -0
- data/app/workflows/spree/price_lists/create.rb +57 -0
- data/app/workflows/spree/price_lists/deactivate.rb +30 -0
- data/app/workflows/spree/price_lists/update.rb +117 -0
- data/app/workflows/spree/products/activate.rb +33 -0
- data/app/workflows/spree/products/approve.rb +52 -0
- data/app/workflows/spree/products/archive.rb +44 -0
- data/app/workflows/spree/products/create.rb +82 -0
- data/app/workflows/spree/products/destroy.rb +35 -0
- data/app/workflows/spree/products/draft.rb +49 -0
- data/app/workflows/spree/products/nested_attributes.rb +242 -0
- data/app/workflows/spree/products/propose.rb +62 -0
- data/app/workflows/spree/products/reject.rb +54 -0
- data/app/workflows/spree/products/update.rb +83 -0
- data/app/workflows/spree/purchase_orders/cancel.rb +57 -0
- data/app/workflows/spree/purchase_orders/close.rb +57 -0
- data/app/workflows/spree/purchase_orders/create.rb +68 -0
- data/app/workflows/spree/purchase_orders/mark_draft.rb +49 -0
- data/app/workflows/spree/purchase_orders/mark_ordered.rb +50 -0
- data/app/workflows/spree/purchase_orders/receive.rb +65 -0
- data/app/workflows/spree/purchase_orders/update.rb +56 -0
- data/app/workflows/spree/receivables/incoming_counter.rb +50 -0
- data/app/workflows/spree/refunds/create.rb +136 -0
- data/app/workflows/spree/refunds/order_payments.rb +129 -0
- data/app/workflows/spree/returns/approve.rb +47 -0
- data/app/workflows/spree/returns/cancel.rb +52 -0
- data/app/workflows/spree/returns/create.rb +135 -0
- data/app/workflows/spree/returns/purchase_label.rb +32 -0
- data/app/workflows/spree/returns/receive.rb +94 -0
- data/app/workflows/spree/returns/refund.rb +134 -0
- data/app/workflows/spree/seller_payouts/complete.rb +80 -0
- data/app/workflows/spree/seller_payouts/sweep.rb +192 -0
- data/app/workflows/spree/seller_requirement_submissions/accept.rb +40 -0
- data/app/workflows/spree/seller_requirement_submissions/create.rb +104 -0
- data/app/workflows/spree/seller_requirement_submissions/reject.rb +45 -0
- data/app/workflows/spree/seller_requirement_submissions/reviewable.rb +19 -0
- data/app/workflows/spree/seller_requirement_submissions/waive.rb +64 -0
- data/app/workflows/spree/seller_transfers/create.rb +131 -0
- data/app/workflows/spree/seller_transfers/reverse.rb +241 -0
- data/app/workflows/spree/sellers/approve.rb +88 -0
- data/app/workflows/spree/sellers/create.rb +72 -0
- data/app/workflows/spree/sellers/invite.rb +61 -0
- data/app/workflows/spree/sellers/reject.rb +52 -0
- data/app/workflows/spree/sellers/reopen_onboarding.rb +55 -0
- data/app/workflows/spree/sellers/start_onboarding.rb +46 -0
- data/app/workflows/spree/sellers/submit_for_review.rb +76 -0
- data/app/workflows/spree/sellers/suspend.rb +55 -0
- data/app/workflows/spree/shipping_labels/purchase.rb +154 -0
- data/app/workflows/spree/shipping_labels/record.rb +102 -0
- data/app/workflows/spree/shipping_labels/refund.rb +77 -0
- data/app/workflows/spree/stock_receipts/recording.rb +165 -0
- data/app/workflows/spree/stock_transfers/cancel.rb +103 -0
- data/app/workflows/spree/stock_transfers/close.rb +56 -0
- data/app/workflows/spree/stock_transfers/create.rb +63 -0
- data/app/workflows/spree/stock_transfers/mark_draft.rb +41 -0
- data/app/workflows/spree/stock_transfers/mark_in_transit.rb +91 -0
- data/app/workflows/spree/stock_transfers/mark_ready.rb +36 -0
- data/app/workflows/spree/stock_transfers/receive.rb +62 -0
- data/app/workflows/spree/stock_transfers/update.rb +55 -0
- data/app/workflows/spree/tax_exemption_certificates/verify.rb +48 -0
- data/app/workflows/spree/variants/create.rb +66 -0
- data/app/workflows/spree/variants/nested_attributes.rb +90 -0
- data/app/workflows/spree/variants/update.rb +55 -0
- data/config/brakeman.ignore +79 -79
- data/config/i18n-tasks.yml +4 -3
- data/config/initializers/mobility.rb +0 -4
- data/config/initializers/spree_store_setup_tasks.rb +4 -0
- data/config/locales/en.yml +952 -189
- data/config/routes.rb +11 -4
- data/db/migrate/20220201103922_add_first_name_and_last_name_to_spree_users.rb +7 -5
- data/db/migrate/20221215151408_add_selected_locale_to_spree_users.rb +6 -4
- data/db/migrate/20250127151258_add_phone_to_spree_users.rb +3 -1
- data/db/migrate/20250207084000_add_accepts_email_marketing_field_to_spree_users_table.rb +4 -2
- data/db/migrate/20250410061306_create_spree_invitations.rb +1 -1
- data/db/migrate/20250605131334_add_missing_fields_to_users.rb +24 -20
- data/db/migrate/20260315100000_add_product_media_support.rb +4 -1
- data/db/migrate/20260613000001_add_store_id_to_spree_role_users.rb +6 -3
- data/db/migrate/20260630000001_add_default_variant_id_to_spree_products.rb +9 -0
- data/db/migrate/20260708160054_create_spree_collections.rb +69 -0
- data/db/migrate/20260710000001_rename_taxons_to_categories.rb +28 -0
- data/db/migrate/20260727000001_add_unique_country_abbr_index_to_spree_states.rb +27 -4
- data/db/migrate/20260728000000_create_spree_customers_and_admin_users.rb +59 -0
- data/db/migrate/20260728000001_rename_prototypes_to_product_types.rb +59 -0
- data/db/migrate/20260728000002_create_spree_delivery_zones.rb +29 -0
- data/db/migrate/20260728000003_create_spree_carts.rb +58 -0
- data/db/migrate/20260728000003_rename_user_id_to_customer_id.rb +30 -0
- data/db/migrate/20260728000004_rename_shipping_to_fulfillment_and_delivery.rb +83 -0
- data/db/migrate/20260728000005_add_fulfillment_type_columns.rb +33 -0
- data/db/migrate/20260729000001_create_typed_adjustment_tables.rb +87 -0
- data/db/migrate/20260729100001_add_checkout_columns_to_spree_carts.rb +15 -0
- data/db/migrate/20260729100002_relax_owner_null_constraints.rb +7 -0
- data/db/migrate/20260729120001_rename_order_totals_to_standard_names.rb +7 -0
- data/db/migrate/20260729130001_create_spree_delivery_method_rules.rb +19 -0
- data/db/migrate/20260729140001_add_coupon_code_to_spree_orders.rb +6 -0
- data/db/migrate/20260729150001_add_store_to_delivery_methods_and_stock_locations.rb +6 -0
- data/db/migrate/20260802190001_create_spree_returns.rb +49 -0
- data/db/migrate/20260802210001_create_spree_exchanges_and_claims.rb +80 -0
- data/db/migrate/20260805100001_rename_return_authorization_reasons_to_return_reasons.rb +109 -0
- data/db/migrate/20260806000001_add_store_id_to_spree_tax_rates_and_categories.rb +16 -0
- data/db/migrate/20260806000001_create_spree_delivery_method_rule_products.rb +22 -0
- data/db/migrate/20260806000002_add_treatment_columns_to_spree_tax_lines.rb +19 -0
- data/db/migrate/20260806000003_create_spree_tax_identifiers.rb +41 -0
- data/db/migrate/20260806000004_add_tax_provider_to_spree_markets.rb +9 -0
- data/db/migrate/20260806000005_add_country_and_state_to_spree_tax_rates.rb +20 -0
- data/db/migrate/20260806100001_create_spree_product_type_custom_field_definitions.rb +17 -0
- data/db/migrate/20260806120001_add_rate_provider_to_delivery_methods.rb +7 -0
- data/db/migrate/20260806120002_add_carrier_columns_to_delivery_rates.rb +13 -0
- data/db/migrate/20260806130001_add_unique_store_type_index_to_spree_integrations.rb +9 -0
- data/db/migrate/20260807000001_add_permissions_to_spree_roles.rb +14 -0
- data/db/migrate/20260807000001_create_spree_companies.rb +66 -0
- data/db/migrate/20260807000003_create_spree_tax_exemption_certificates.rb +31 -0
- data/db/migrate/20260807120001_remove_claim_type_from_spree_claims.rb +5 -0
- data/db/migrate/20260807130001_add_country_state_codes_to_consumers.rb +28 -0
- data/db/migrate/20260807150001_reindex_spree_categories_by_store.rb +42 -0
- data/db/migrate/20260809000001_rename_metafields_to_custom_fields.rb +126 -0
- data/db/migrate/20260809100001_support_multi_rate_delivery_methods.rb +35 -0
- data/db/migrate/20260809120001_consolidate_metadata_columns.rb +120 -0
- data/db/migrate/20260809150001_promote_shipping_categories_to_delivery_profiles.rb +153 -0
- data/db/migrate/20260809170001_create_spree_channel_stock_locations.rb +17 -0
- data/db/migrate/20260809200001_add_rich_text_columns_for_action_text_removal.rb +11 -0
- data/db/migrate/20260810000001_rename_digitals_to_digital_assets.rb +38 -0
- data/db/migrate/20260811000001_add_delivery_tracking_to_fulfillments.rb +17 -0
- data/db/migrate/20260812000001_add_provider_type_to_spree_digital_assets.rb +7 -0
- data/db/migrate/20260812000002_add_metadata_to_spree_digital_assets.rb +11 -0
- data/db/migrate/20260813000001_create_spree_number_sequences.rb +13 -0
- data/db/migrate/20260813120001_add_setup_token_to_spree_stores.rb +11 -0
- data/db/migrate/20260813130001_add_capture_method_to_payment_methods.rb +17 -0
- data/db/migrate/20260813130001_add_unique_indexes_to_spree_data_feeds.rb +10 -0
- data/db/migrate/20260814000001_add_customs_fields_to_spree_variants.rb +7 -0
- data/db/migrate/20260814000001_rename_stock_items_to_stock_levels.rb +72 -0
- data/db/migrate/20260814000002_add_typed_stock_movements.rb +25 -0
- data/db/migrate/20260815000001_add_audience_to_spree_refresh_tokens.rb +14 -0
- data/db/migrate/20260815000002_add_resource_to_spree_roles.rb +190 -0
- data/db/migrate/20260816000001_create_spree_sellers.rb +59 -0
- data/db/migrate/20260816000002_add_seller_to_spree_products.rb +10 -0
- data/db/migrate/20260816210001_create_spree_commission_rates.rb +229 -0
- data/db/migrate/20260816210002_create_spree_commission_lines.rb +72 -0
- data/db/migrate/20260817000001_add_seller_to_spree_line_items.rb +15 -0
- data/db/migrate/20260817000002_add_seller_and_delivery_profile_to_spree_variants.rb +17 -0
- data/db/migrate/20260818000001_create_spree_external_references.rb +33 -0
- data/db/migrate/20260818000001_create_spree_seller_requirements.rb +60 -0
- data/db/migrate/20260818000001_rename_spree_payments_state_to_status.rb +5 -0
- data/db/migrate/20260818000002_add_price_source_to_spree_line_items.rb +9 -0
- data/db/migrate/20260818090001_rename_assets_to_media.rb +10 -0
- data/db/migrate/20260819000001_create_spree_seller_requirement_custom_fields.rb +15 -0
- data/db/migrate/20260819000001_replace_payment_method_display_on_with_storefront_visible.rb +25 -0
- data/db/migrate/20260819000002_rename_spree_gift_cards_state_to_status.rb +5 -0
- data/db/migrate/20260820000001_add_seller_business_identity_and_stock_locations.rb +17 -0
- data/db/migrate/20260820000001_create_spree_order_groups.rb +33 -0
- data/db/migrate/20260820000002_add_order_group_to_spree_orders_and_payments.rb +14 -0
- data/db/migrate/20260820000003_create_spree_payment_splits.rb +21 -0
- data/db/migrate/20260820000004_add_order_to_spree_refunds.rb +32 -0
- data/db/migrate/20260821000001_add_claimed_amount_to_spree_payment_splits.rb +14 -0
- data/db/migrate/20260822000001_create_spree_seller_transfers.rb +94 -0
- data/db/migrate/20260822000002_create_spree_seller_payouts.rb +48 -0
- data/db/migrate/20260822000003_add_payout_account_to_spree_sellers.rb +11 -0
- data/db/migrate/20260824000001_add_store_to_spree_media.rb +16 -0
- data/db/migrate/20260825000001_create_spree_catalogs.rb +40 -0
- data/db/migrate/20260826000001_add_owner_to_spree_addresses.rb +30 -0
- data/db/migrate/20260826000002_create_spree_product_submissions.rb +28 -0
- data/db/migrate/20260827000001_add_seller_to_spree_exports.rb +5 -0
- data/db/migrate/20260828100001_unify_import_and_export_tenancy.rb +79 -0
- data/db/migrate/20260830000001_add_catalog_to_spree_price_lists.rb +47 -0
- data/db/migrate/20260830000002_add_po_number_to_purchases.rb +16 -0
- data/db/migrate/20260830000002_add_price_adjustment_to_spree_price_lists.rb +14 -0
- data/db/migrate/20260831000001_add_description_to_spree_catalogs.rb +7 -0
- data/db/migrate/20260831000002_add_quantity_rules_to_spree_variants.rb +18 -0
- data/db/migrate/20260831000003_create_spree_catalog_terms.rb +35 -0
- data/db/migrate/20260831100001_create_spree_package_types.rb +38 -0
- data/db/migrate/20260831100002_add_carton_details_to_spree_variants.rb +10 -0
- data/db/migrate/20260831100003_add_unpriced_to_spree_delivery_rates.rb +8 -0
- data/db/migrate/20260901000001_add_seller_to_spree_delivery_methods.rb +11 -0
- data/db/migrate/20260902000001_add_store_and_filter_key_to_custom_field_definitions.rb +143 -0
- data/db/migrate/20260902000002_add_eu_legal_compliance.rb +68 -0
- data/db/migrate/20260902000002_replace_order_cancellation_tables_with_cancel_columns.rb +88 -0
- data/db/migrate/20260902100001_rename_wished_items_to_wishlist_items.rb +8 -0
- data/db/migrate/20260902100002_rename_promo_total_to_discount_total.rb +9 -0
- data/db/migrate/20260902100003_rename_address_name_and_postal_code_columns.rb +24 -0
- data/db/migrate/20260902100004_rename_option_presentation_to_label.rb +13 -0
- data/db/migrate/20260903000001_create_spree_shipping_labels_and_deliveries.rb +73 -0
- data/db/migrate/20260903120000_create_spree_saved_reports.rb +57 -0
- data/db/migrate/20260904000001_add_returns_enabled_to_stock_locations.rb +14 -0
- data/db/migrate/20260906000001_add_commission_total_to_orders.rb +22 -0
- data/db/migrate/20260907000001_add_inventory_operations.rb +113 -0
- data/db/migrate/20260907000001_add_min_quantity_to_spree_prices.rb +28 -0
- data/db/migrate/20260907000002_create_spree_price_adjustment_tiers.rb +19 -0
- data/db/migrate/20260908000001_add_seller_to_spree_package_types.rb +78 -0
- data/db/migrate/20260910000001_add_stock_receipts.rb +44 -0
- data/db/migrate/20260910000002_add_counters_to_spree_stock_levels.rb +6 -0
- data/db/migrate/20260910120000_index_reporting_time_columns.rb +12 -0
- data/db/migrate/20260912120000_index_reporting_lifetime_and_promotion_columns.rb +19 -0
- data/db/migrate/20260914000001_add_settlement_to_spree_seller_transfers.rb +18 -0
- data/db/migrate/20260914230000_add_store_to_spree_option_types.rb +46 -0
- data/db/migrate/20260916000001_order_operation_actors_polymorphic.rb +30 -0
- data/db/sample_data/collections.rb +58 -0
- data/db/sample_data/custom_field_definitions.rb +9 -0
- data/db/sample_data/digital_products.rb +26 -0
- data/db/sample_data/fulfillment.rb +88 -0
- data/db/sample_data/options.rb +25 -1
- data/db/sample_data/orders.rb +53 -30
- data/db/sample_data/payment_methods.rb +2 -2
- data/db/sample_data/price_list_prices.csv +25 -0
- data/db/sample_data/product_type_categories.rb +27 -0
- data/db/sample_data/product_types.rb +83 -0
- data/db/sample_data/products.csv +39 -38
- data/db/sample_data/wholesale.rb +42 -3
- data/lib/generators/spree/api_resource/api_resource_generator.rb +64 -6
- data/lib/generators/spree/api_resource/templates/admin_controller.rb.tt +5 -0
- data/lib/generators/spree/api_resource/templates/admin_controller_spec.rb.tt +3 -0
- data/lib/generators/spree/api_resource/templates/store_controller_spec.rb.tt +4 -1
- data/lib/generators/spree/authentication/dummy/templates/create_spree_admin_users.rb.tt +1 -0
- data/lib/generators/spree/controller_decorator/controller_decorator_generator.rb +4 -4
- data/lib/generators/spree/dummy/dummy_generator.rb +5 -12
- data/lib/generators/spree/dummy/templates/rails/test.rb +5 -0
- data/lib/generators/spree/model/model_generator.rb +46 -7
- data/lib/generators/spree/model/templates/create_table_migration.rb.tt +9 -0
- data/lib/generators/spree/model/templates/model.rb.tt +17 -7
- data/lib/spree/category_permalink_deduplicator.rb +328 -0
- data/lib/spree/checkout/default_requirements.rb +134 -0
- data/lib/spree/checkout/registry.rb +164 -0
- data/lib/spree/checkout/requirement.rb +49 -0
- data/lib/spree/checkout/requirements.rb +61 -0
- data/lib/spree/checkout/step.rb +52 -0
- data/lib/spree/core/configuration.rb +112 -63
- data/lib/spree/core/controller_helpers/store.rb +8 -9
- data/lib/spree/core/dependencies.rb +324 -71
- data/lib/spree/core/dependencies_helper.rb +4 -0
- data/lib/spree/core/engine.rb +360 -75
- data/lib/spree/core/number_generator.rb +37 -33
- data/lib/spree/core/permission_configuration.rb +183 -91
- data/lib/spree/core/permissions/default_catalog.rb +236 -0
- data/lib/spree/core/permissions/entry.rb +15 -0
- data/lib/spree/core/permissions/scope.rb +76 -0
- data/lib/spree/core/preferences/masking.rb +24 -2
- data/lib/spree/core/preferences/preferable.rb +52 -2
- data/lib/spree/core/preferences/preferable_class_methods.rb +41 -2
- data/lib/spree/core/preferences/runtime_configuration.rb +142 -9
- data/lib/spree/core/previews/admin_user_preview.rb +0 -8
- data/lib/spree/core/previews/invitation_preview.rb +1 -1
- data/lib/spree/core/previews/preview_data.rb +2 -2
- data/lib/spree/core/previews/seller_user_preview.rb +14 -0
- data/lib/spree/core/pricing/context.rb +28 -8
- data/lib/spree/core/pricing/price_resolution.rb +150 -0
- data/lib/spree/core/pricing/resolver.rb +17 -107
- data/lib/spree/core/ransack_configuration.rb +3 -3
- data/lib/spree/core/routes.rb +4 -6
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +446 -59
- data/lib/spree/events/adapters/base.rb +42 -15
- data/lib/spree/hooks.rb +146 -0
- data/lib/spree/iso_data.rb +188 -0
- data/lib/spree/measurement.rb +113 -0
- data/lib/spree/money.rb +70 -0
- data/lib/spree/number_generators/registry.rb +80 -0
- data/lib/spree/reporting/adapters/base.rb +71 -0
- data/lib/spree/reporting/adapters/live.rb +677 -0
- data/lib/spree/reporting/counter_result.rb +19 -0
- data/lib/spree/reporting/counters.rb +33 -0
- data/lib/spree/reporting/default_vocabulary.rb +705 -0
- data/lib/spree/reporting/hydration.rb +64 -0
- data/lib/spree/reporting/query.rb +487 -0
- data/lib/spree/reporting/registry.rb +294 -0
- data/lib/spree/reporting/result.rb +10 -0
- data/lib/spree/reporting/schema.rb +124 -0
- data/lib/spree/reporting.rb +49 -0
- data/lib/spree/service_module.rb +6 -0
- data/lib/spree/store_scope_guard.rb +180 -0
- data/lib/spree/testing_support/action_text.rb +33 -0
- data/lib/spree/testing_support/common_rake.rb +4 -66
- data/lib/spree/testing_support/country_pool.rb +50 -0
- data/lib/spree/testing_support/extension_rake.rb +2 -6
- data/lib/spree/testing_support/factories/address_factory.rb +45 -15
- data/lib/spree/testing_support/factories/api_key_factory.rb +1 -1
- data/lib/spree/testing_support/factories/calculator_factory.rb +0 -3
- data/lib/spree/testing_support/factories/cart_factory.rb +60 -0
- data/lib/spree/testing_support/factories/catalog_factory.rb +37 -0
- data/lib/spree/testing_support/factories/category_factory.rb +21 -0
- data/lib/spree/testing_support/factories/claim_factory.rb +33 -0
- data/lib/spree/testing_support/factories/classification_factory.rb +3 -2
- data/lib/spree/testing_support/factories/collection_factory.rb +25 -0
- data/lib/spree/testing_support/factories/collection_rule_factory.rb +47 -0
- data/lib/spree/testing_support/factories/commission_rate_factory.rb +75 -0
- data/lib/spree/testing_support/factories/company_factory.rb +31 -0
- data/lib/spree/testing_support/factories/consent_record_factory.rb +10 -0
- data/lib/spree/testing_support/factories/country_factory.rb +28 -9
- data/lib/spree/testing_support/factories/custom_field_definition_factory.rb +79 -0
- data/lib/spree/testing_support/factories/custom_field_factory.rb +64 -0
- data/lib/spree/testing_support/factories/customer_group_user_factory.rb +1 -1
- data/lib/spree/testing_support/factories/data_request_factory.rb +17 -0
- data/lib/spree/testing_support/factories/delivery_factory.rb +13 -0
- data/lib/spree/testing_support/factories/delivery_method_factory.rb +47 -0
- data/lib/spree/testing_support/factories/delivery_origin_group_factory.rb +5 -0
- data/lib/spree/testing_support/factories/delivery_profile_factory.rb +9 -0
- data/lib/spree/testing_support/factories/delivery_rate_factory.rb +7 -0
- data/lib/spree/testing_support/factories/delivery_zone_factory.rb +34 -0
- data/lib/spree/testing_support/factories/digital_asset_factory.rb +13 -0
- data/lib/spree/testing_support/factories/digital_link_factory.rb +1 -1
- data/lib/spree/testing_support/factories/discount_factory.rb +9 -0
- data/lib/spree/testing_support/factories/exchange_factory.rb +50 -0
- data/lib/spree/testing_support/factories/external_reference_factory.rb +8 -0
- data/lib/spree/testing_support/factories/fee_factory.rb +8 -0
- data/lib/spree/testing_support/factories/fulfillment_factory.rb +32 -0
- data/lib/spree/testing_support/factories/fulfillment_item_factory.rb +17 -0
- data/lib/spree/testing_support/factories/gateway_customer_factory.rb +1 -1
- data/lib/spree/testing_support/factories/gift_card_factory.rb +2 -2
- data/lib/spree/testing_support/factories/import_factory.rb +33 -1
- data/lib/spree/testing_support/factories/line_item_factory.rb +10 -5
- data/lib/spree/testing_support/factories/market_factory.rb +5 -12
- data/lib/spree/testing_support/factories/media_factory.rb +36 -0
- data/lib/spree/testing_support/factories/newsletter_subscriber_factory.rb +1 -1
- data/lib/spree/testing_support/factories/number_sequence_factory.rb +7 -0
- data/lib/spree/testing_support/factories/options_factory.rb +5 -5
- data/lib/spree/testing_support/factories/order_factory.rb +39 -23
- data/lib/spree/testing_support/factories/order_group_factory.rb +29 -0
- data/lib/spree/testing_support/factories/package_type_factory.rb +36 -0
- data/lib/spree/testing_support/factories/payment_factory.rb +7 -7
- data/lib/spree/testing_support/factories/payment_method_factory.rb +5 -5
- data/lib/spree/testing_support/factories/payment_session_factory.rb +10 -6
- data/lib/spree/testing_support/factories/payment_setup_session_factory.rb +2 -2
- data/lib/spree/testing_support/factories/payment_split_factory.rb +10 -0
- data/lib/spree/testing_support/factories/price_adjustment_tier_factory.rb +7 -0
- data/lib/spree/testing_support/factories/price_factory.rb +6 -0
- data/lib/spree/testing_support/factories/price_rule_factory.rb +0 -10
- data/lib/spree/testing_support/factories/product_collection_factory.rb +8 -0
- data/lib/spree/testing_support/factories/product_factory.rb +35 -7
- data/lib/spree/testing_support/factories/product_type_custom_field_definition_factory.rb +10 -0
- data/lib/spree/testing_support/factories/product_type_factory.rb +12 -0
- data/lib/spree/testing_support/factories/promotion_factory.rb +4 -0
- data/lib/spree/testing_support/factories/promotion_rule_factory.rb +1 -1
- data/lib/spree/testing_support/factories/purchase_order_factory.rb +49 -0
- data/lib/spree/testing_support/factories/refresh_token_factory.rb +2 -0
- data/lib/spree/testing_support/factories/refund_factory.rb +1 -2
- data/lib/spree/testing_support/factories/return_factory.rb +52 -0
- data/lib/spree/testing_support/factories/return_reason_factory.rb +19 -0
- data/lib/spree/testing_support/factories/role_factory.rb +1 -0
- data/lib/spree/testing_support/factories/saved_report_factory.rb +7 -0
- data/lib/spree/testing_support/factories/seller_factory.rb +34 -0
- data/lib/spree/testing_support/factories/seller_payout_factory.rb +14 -0
- data/lib/spree/testing_support/factories/seller_requirement_factory.rb +61 -0
- data/lib/spree/testing_support/factories/seller_requirement_submission_factory.rb +32 -0
- data/lib/spree/testing_support/factories/seller_transfer_factory.rb +21 -0
- data/lib/spree/testing_support/factories/shipping_label_factory.rb +44 -0
- data/lib/spree/testing_support/factories/state_factory.rb +18 -5
- data/lib/spree/testing_support/factories/stock_level_factory.rb +24 -0
- data/lib/spree/testing_support/factories/stock_location_factory.rb +12 -6
- data/lib/spree/testing_support/factories/stock_movement_factory.rb +20 -3
- data/lib/spree/testing_support/factories/stock_receipt_factory.rb +37 -0
- data/lib/spree/testing_support/factories/stock_reservation_factory.rb +11 -8
- data/lib/spree/testing_support/factories/stock_transfer_factory.rb +53 -6
- data/lib/spree/testing_support/factories/store_credit_factory.rb +1 -3
- data/lib/spree/testing_support/factories/supplier_factory.rb +17 -0
- data/lib/spree/testing_support/factories/tax_exemption_certificate_factory.rb +18 -0
- data/lib/spree/testing_support/factories/tax_identifier_factory.rb +33 -0
- data/lib/spree/testing_support/factories/tax_line_factory.rb +19 -0
- data/lib/spree/testing_support/factories/tax_rate_factory.rb +5 -2
- data/lib/spree/testing_support/factories/taxon_factory.rb +6 -23
- data/lib/spree/testing_support/factories/taxonomy_factory.rb +8 -0
- data/lib/spree/testing_support/factories/user_factory.rb +8 -13
- data/lib/spree/testing_support/factories/variant_factory.rb +1 -1
- data/lib/spree/testing_support/factories/wishlist_factory.rb +1 -1
- data/lib/spree/testing_support/factories/wishlist_item_factory.rb +10 -0
- data/lib/spree/testing_support/factories/zone_factory.rb +2 -25
- data/lib/spree/testing_support/factories/zone_member_factory.rb +2 -1
- data/lib/spree/testing_support/factories.rb +1 -6
- data/lib/spree/testing_support/imports.rb +16 -0
- data/lib/spree/testing_support/label_provider.rb +49 -0
- data/lib/spree/testing_support/lifecycle_events.rb +6 -1
- data/lib/spree/testing_support/metadata.rb +38 -36
- data/lib/spree/testing_support/order_walkthrough.rb +46 -36
- data/lib/spree/testing_support/preferences.rb +39 -0
- data/lib/spree/testing_support/purchase_order.rb +111 -0
- data/lib/spree/testing_support/store.rb +6 -2
- data/lib/spree/testing_support/tax_identifier_validators.rb +68 -0
- data/lib/spree/translations.rb +139 -5
- data/lib/spree/upgrades/5_4_to_5_5/manifest.yml +1 -1
- data/lib/spree/upgrades/5_5_to_5_6/manifest.yml +17 -9
- data/lib/spree/upgrades/5_6_to_6_0/manifest.yml +683 -0
- data/lib/spree/validators.rb +74 -0
- data/lib/spree/workflow.rb +335 -0
- data/lib/tasks/backfill_actor_types.rake +35 -0
- data/lib/tasks/backfill_custom_field_definition_stores.rake +82 -0
- data/lib/tasks/backfill_import_export_tenancy.rake +93 -0
- data/lib/tasks/backfill_library_media_placements.rake +29 -0
- data/lib/tasks/backfill_media_store_ids.rake +70 -0
- data/lib/tasks/backfill_reason_store_ids.rake +28 -0
- data/lib/tasks/capture_methods_migration.rake +30 -0
- data/lib/tasks/carts_migration.rake +113 -0
- data/lib/tasks/categories_and_collections.rake +188 -0
- data/lib/tasks/cli.rake +22 -3
- data/lib/tasks/consolidate_metadata.rake +73 -0
- data/lib/tasks/core.rake +1 -11
- data/lib/tasks/deliveries_migration.rake +52 -0
- data/lib/tasks/delivery_method_rules_migration.rake +51 -0
- data/lib/tasks/delivery_migration.rake +213 -0
- data/lib/tasks/delivery_profiles_migration.rake +109 -0
- data/lib/tasks/fold_store_credit_categories.rake +40 -0
- data/lib/tasks/fulfillment_statuses_migration.rake +59 -0
- data/lib/tasks/inventory_operations_migration.rake +223 -0
- data/lib/tasks/markets.rake +7 -2
- data/lib/tasks/media.rake +2 -2
- data/lib/tasks/media_class_rename.rake +56 -0
- data/lib/tasks/migrate_country_state_codes.rake +228 -0
- data/lib/tasks/migrate_promotion_option_value_rules.rake +124 -0
- data/lib/tasks/migrate_returns.rake +322 -0
- data/lib/tasks/migrate_rich_text_to_columns.rake +128 -0
- data/lib/tasks/migrate_users_to_customers.rake +161 -0
- data/lib/tasks/order_coupon_code_backfill.rake +32 -0
- data/lib/tasks/order_market_backfill.rake +27 -0
- data/lib/tasks/package_types.rake +62 -0
- data/lib/tasks/price_history.rake +49 -6
- data/lib/tasks/products.rake +21 -2
- data/lib/tasks/remove_master_variant.rake +58 -0
- data/lib/tasks/rich_text.rake +44 -0
- data/lib/tasks/seller_sample_data.rake +142 -0
- data/lib/tasks/setup.rake +18 -0
- data/lib/tasks/single_store_associations.rake +11 -0
- data/lib/tasks/stock.rake +15 -0
- data/lib/tasks/store_binding_migration.rake +33 -0
- data/lib/tasks/store_settings.rake +105 -0
- data/lib/tasks/tax_zones_migration.rake +147 -0
- data/lib/tasks/taxons.rake +9 -10
- data/lib/tasks/typed_adjustments_migration.rake +189 -0
- data/lib/tasks/typed_stock_movements_migration.rake +250 -0
- data/lib/tasks/upgrade.rake +13 -8
- data/spec/fixtures/files/eu_vat_numbers.txt +56 -0
- data/spec/fixtures/files/price_list_prices_import.csv +4 -0
- data/spec/fixtures/files/products_import.csv +1 -1
- data/spec/fixtures/tiny-video.mp4 +0 -0
- metadata +798 -546
- data/app/assets/config/spree_core_manifest.js +0 -4
- data/app/assets/images/google_on_white_hdpi.png +0 -0
- data/app/assets/images/logo.png +0 -0
- data/app/assets/images/payment_icons/ach.svg +0 -1
- data/app/assets/images/payment_icons/achdirectdebit.svg +0 -1
- data/app/assets/images/payment_icons/ada.svg +0 -1
- data/app/assets/images/payment_icons/adyen.svg +0 -1
- data/app/assets/images/payment_icons/affinbank.svg +0 -1
- data/app/assets/images/payment_icons/affirm.svg +0 -1
- data/app/assets/images/payment_icons/afterpay.svg +0 -1
- data/app/assets/images/payment_icons/airtel_money.svg +0 -1
- data/app/assets/images/payment_icons/airteltigo_mobile_money.svg +0 -1
- data/app/assets/images/payment_icons/alandsbanken.svg +0 -1
- data/app/assets/images/payment_icons/alipay.svg +0 -1
- data/app/assets/images/payment_icons/alipay_hk.svg +0 -1
- data/app/assets/images/payment_icons/alliancebank.svg +0 -1
- data/app/assets/images/payment_icons/alma.svg +0 -1
- data/app/assets/images/payment_icons/amazon.svg +0 -1
- data/app/assets/images/payment_icons/ambank.svg +0 -1
- data/app/assets/images/payment_icons/american_express.svg +0 -1
- data/app/assets/images/payment_icons/apecoin.svg +0 -1
- data/app/assets/images/payment_icons/apple_pay.svg +0 -1
- data/app/assets/images/payment_icons/arbitrum.svg +0 -1
- data/app/assets/images/payment_icons/atome.svg +0 -1
- data/app/assets/images/payment_icons/authorizenet.svg +0 -1
- data/app/assets/images/payment_icons/avalanche.svg +0 -1
- data/app/assets/images/payment_icons/bacs.svg +0 -1
- data/app/assets/images/payment_icons/bancontact.svg +0 -1
- data/app/assets/images/payment_icons/bangkokbank.svg +0 -1
- data/app/assets/images/payment_icons/bankislam.svg +0 -1
- data/app/assets/images/payment_icons/bankmuamalat.svg +0 -1
- data/app/assets/images/payment_icons/bankofamerica.svg +0 -1
- data/app/assets/images/payment_icons/bankrakyat.svg +0 -1
- data/app/assets/images/payment_icons/banktransfer.svg +0 -1
- data/app/assets/images/payment_icons/base.svg +0 -1
- data/app/assets/images/payment_icons/becs.svg +0 -1
- data/app/assets/images/payment_icons/benefit.svg +0 -1
- data/app/assets/images/payment_icons/billie.svg +0 -1
- data/app/assets/images/payment_icons/bitcoin.svg +0 -1
- data/app/assets/images/payment_icons/bitcoin_cash.svg +0 -1
- data/app/assets/images/payment_icons/bizum.svg +0 -1
- data/app/assets/images/payment_icons/blik.svg +0 -1
- data/app/assets/images/payment_icons/bnbchain.svg +0 -1
- data/app/assets/images/payment_icons/bogus.svg +0 -1
- data/app/assets/images/payment_icons/bogus_app_coin.svg +0 -1
- data/app/assets/images/payment_icons/boleto.svg +0 -1
- data/app/assets/images/payment_icons/boost.svg +0 -1
- data/app/assets/images/payment_icons/braintree.svg +0 -1
- data/app/assets/images/payment_icons/buckaroopaybybank.svg +0 -1
- data/app/assets/images/payment_icons/busd.svg +0 -1
- data/app/assets/images/payment_icons/cartes_bancaires.svg +0 -1
- data/app/assets/images/payment_icons/cash.svg +0 -1
- data/app/assets/images/payment_icons/cashappafterpay.svg +0 -1
- data/app/assets/images/payment_icons/cashapppay.svg +0 -1
- data/app/assets/images/payment_icons/checkout_finance.svg +0 -1
- data/app/assets/images/payment_icons/chinabank.svg +0 -1
- data/app/assets/images/payment_icons/clearpay.svg +0 -1
- data/app/assets/images/payment_icons/collector_bank.svg +0 -1
- data/app/assets/images/payment_icons/dai.svg +0 -1
- data/app/assets/images/payment_icons/dana.svg +0 -1
- data/app/assets/images/payment_icons/dankort.svg +0 -1
- data/app/assets/images/payment_icons/danske_bank.svg +0 -1
- data/app/assets/images/payment_icons/deutschebank.svg +0 -1
- data/app/assets/images/payment_icons/diners_club.svg +0 -1
- data/app/assets/images/payment_icons/directbanktransferlatinamerica.svg +0 -1
- data/app/assets/images/payment_icons/discover.svg +0 -1
- data/app/assets/images/payment_icons/dogecoin.svg +0 -1
- data/app/assets/images/payment_icons/duitnow.svg +0 -1
- data/app/assets/images/payment_icons/eft_secure.svg +0 -1
- data/app/assets/images/payment_icons/eftpos_au.svg +0 -1
- data/app/assets/images/payment_icons/eftposau.svg +0 -1
- data/app/assets/images/payment_icons/elo.svg +0 -1
- data/app/assets/images/payment_icons/eos.svg +0 -1
- data/app/assets/images/payment_icons/eps.svg +0 -1
- data/app/assets/images/payment_icons/ethereum.svg +0 -1
- data/app/assets/images/payment_icons/eurobonuscheckout.svg +0 -1
- data/app/assets/images/payment_icons/ezcash.svg +0 -1
- data/app/assets/images/payment_icons/fantom.svg +0 -1
- data/app/assets/images/payment_icons/fpx.svg +0 -1
- data/app/assets/images/payment_icons/gcash.svg +0 -1
- data/app/assets/images/payment_icons/generic.svg +0 -1
- data/app/assets/images/payment_icons/genericbank.svg +0 -1
- data/app/assets/images/payment_icons/gift-card.svg +0 -1
- data/app/assets/images/payment_icons/giropay.svg +0 -1
- data/app/assets/images/payment_icons/glbepaypal.svg +0 -1
- data/app/assets/images/payment_icons/gmobanktransfer.svg +0 -1
- data/app/assets/images/payment_icons/gnosis.svg +0 -1
- data/app/assets/images/payment_icons/google_pay.svg +0 -1
- data/app/assets/images/payment_icons/google_wallet.svg +0 -1
- data/app/assets/images/payment_icons/gopay.svg +0 -1
- data/app/assets/images/payment_icons/grabpay.svg +0 -1
- data/app/assets/images/payment_icons/gusd.svg +0 -1
- data/app/assets/images/payment_icons/handelsbanken.svg +0 -1
- data/app/assets/images/payment_icons/hongleongbank.svg +0 -1
- data/app/assets/images/payment_icons/hypercard.svg +0 -1
- data/app/assets/images/payment_icons/hypercash.svg +0 -1
- data/app/assets/images/payment_icons/ideal.svg +0 -1
- data/app/assets/images/payment_icons/in3viaideal.svg +0 -1
- data/app/assets/images/payment_icons/inbank.svg +0 -1
- data/app/assets/images/payment_icons/jcb.svg +0 -1
- data/app/assets/images/payment_icons/kakao_pay.svg +0 -1
- data/app/assets/images/payment_icons/kasikornbank.svg +0 -1
- data/app/assets/images/payment_icons/klarna-pay-later.svg +0 -1
- data/app/assets/images/payment_icons/klarna-pay-now.svg +0 -1
- data/app/assets/images/payment_icons/klarna-slice-it.svg +0 -1
- data/app/assets/images/payment_icons/klarna.svg +0 -1
- data/app/assets/images/payment_icons/knet.svg +0 -1
- data/app/assets/images/payment_icons/krungthaibank.svg +0 -1
- data/app/assets/images/payment_icons/landbank.svg +0 -1
- data/app/assets/images/payment_icons/laybuybyklarna.svg +0 -1
- data/app/assets/images/payment_icons/litecoin.svg +0 -1
- data/app/assets/images/payment_icons/lunchcheck.svg +0 -1
- data/app/assets/images/payment_icons/mach.svg +0 -1
- data/app/assets/images/payment_icons/mada.svg +0 -1
- data/app/assets/images/payment_icons/maestro.svg +0 -1
- data/app/assets/images/payment_icons/master.svg +0 -1
- data/app/assets/images/payment_icons/mayabank.svg +0 -1
- data/app/assets/images/payment_icons/maybank.svg +0 -1
- data/app/assets/images/payment_icons/maybankm2u.svg +0 -1
- data/app/assets/images/payment_icons/maybankqrpay.svg +0 -1
- data/app/assets/images/payment_icons/mbway.svg +0 -1
- data/app/assets/images/payment_icons/mcash.svg +0 -1
- data/app/assets/images/payment_icons/medicinosbankas.svg +0 -1
- data/app/assets/images/payment_icons/mercadopago.svg +0 -1
- data/app/assets/images/payment_icons/metrobank.svg +0 -1
- data/app/assets/images/payment_icons/mobilepay.svg +0 -1
- data/app/assets/images/payment_icons/momopay.svg +0 -1
- data/app/assets/images/payment_icons/monero.svg +0 -1
- data/app/assets/images/payment_icons/mtn_mobile_money.svg +0 -1
- data/app/assets/images/payment_icons/mybank.svg +0 -1
- data/app/assets/images/payment_icons/naver_pay.svg +0 -1
- data/app/assets/images/payment_icons/nelo.svg +0 -1
- data/app/assets/images/payment_icons/netbanking.svg +0 -1
- data/app/assets/images/payment_icons/novalnetdirectdebitach.svg +0 -1
- data/app/assets/images/payment_icons/nubank.svg +0 -1
- data/app/assets/images/payment_icons/ocbcbank.svg +0 -1
- data/app/assets/images/payment_icons/offlinebanktransferlatinamerica.svg +0 -1
- data/app/assets/images/payment_icons/ola_money.svg +0 -1
- data/app/assets/images/payment_icons/oney.svg +0 -1
- data/app/assets/images/payment_icons/onlinebanking.svg +0 -1
- data/app/assets/images/payment_icons/onlinebanktransfer.svg +0 -1
- data/app/assets/images/payment_icons/orangemobilemoney.svg +0 -1
- data/app/assets/images/payment_icons/otpbank.svg +0 -1
- data/app/assets/images/payment_icons/oxxo.svg +0 -1
- data/app/assets/images/payment_icons/paybybank.svg +0 -1
- data/app/assets/images/payment_icons/paybybankmollie.svg +0 -1
- data/app/assets/images/payment_icons/paybybankus.svg +0 -1
- data/app/assets/images/payment_icons/paycash.svg +0 -1
- data/app/assets/images/payment_icons/payco.svg +0 -1
- data/app/assets/images/payment_icons/payeverpaybybank.svg +0 -1
- data/app/assets/images/payment_icons/payme.svg +0 -1
- data/app/assets/images/payment_icons/paynow.svg +0 -1
- data/app/assets/images/payment_icons/paynowmbank.svg +0 -1
- data/app/assets/images/payment_icons/paypal.svg +0 -1
- data/app/assets/images/payment_icons/paypo.svg +0 -1
- data/app/assets/images/payment_icons/payrexxbanktransfer.svg +0 -1
- data/app/assets/images/payment_icons/payrexxpaybybank.svg +0 -1
- data/app/assets/images/payment_icons/paysafecash.svg +0 -1
- data/app/assets/images/payment_icons/pix.svg +0 -1
- data/app/assets/images/payment_icons/polygon.svg +0 -1
- data/app/assets/images/payment_icons/przelewy24.svg +0 -1
- data/app/assets/images/payment_icons/publicbank.svg +0 -1
- data/app/assets/images/payment_icons/publicbank_pbe.svg +0 -1
- data/app/assets/images/payment_icons/qr_promptpay.svg +0 -1
- data/app/assets/images/payment_icons/rabobank.svg +0 -1
- data/app/assets/images/payment_icons/revolut.svg +0 -1
- data/app/assets/images/payment_icons/rhbbank.svg +0 -1
- data/app/assets/images/payment_icons/riverty.svg +0 -1
- data/app/assets/images/payment_icons/safetypaybanktransfer.svg +0 -1
- data/app/assets/images/payment_icons/samsung_pay.svg +0 -1
- data/app/assets/images/payment_icons/satispay.svg +0 -1
- data/app/assets/images/payment_icons/scalapay.svg +0 -1
- data/app/assets/images/payment_icons/scotiabank.svg +0 -1
- data/app/assets/images/payment_icons/seabankid.svg +0 -1
- data/app/assets/images/payment_icons/seabankph.svg +0 -1
- data/app/assets/images/payment_icons/sepa_bank_transfer.svg +0 -1
- data/app/assets/images/payment_icons/sepadebit.svg +0 -22
- data/app/assets/images/payment_icons/sepadirectdebit.svg +0 -1
- data/app/assets/images/payment_icons/seveneleven.svg +0 -1
- data/app/assets/images/payment_icons/shib.svg +0 -1
- data/app/assets/images/payment_icons/shopcash.svg +0 -1
- data/app/assets/images/payment_icons/siauliubankas.svg +0 -1
- data/app/assets/images/payment_icons/skeps.svg +0 -1
- data/app/assets/images/payment_icons/snap_checkout.svg +0 -1
- data/app/assets/images/payment_icons/sofort.svg +0 -1
- data/app/assets/images/payment_icons/softbank.svg +0 -1
- data/app/assets/images/payment_icons/spei.svg +0 -1
- data/app/assets/images/payment_icons/storecredit.svg +0 -1
- data/app/assets/images/payment_icons/stripe.svg +0 -1
- data/app/assets/images/payment_icons/sveacheckout.svg +0 -1
- data/app/assets/images/payment_icons/swedbank.svg +0 -1
- data/app/assets/images/payment_icons/swish.svg +0 -1
- data/app/assets/images/payment_icons/tbibank.svg +0 -1
- data/app/assets/images/payment_icons/thanachartbank.svg +0 -1
- data/app/assets/images/payment_icons/tnmmoney.svg +0 -1
- data/app/assets/images/payment_icons/touchngo.svg +0 -1
- data/app/assets/images/payment_icons/trustly.svg +0 -1
- data/app/assets/images/payment_icons/twint.svg +0 -1
- data/app/assets/images/payment_icons/uaevisa.svg +0 -1
- data/app/assets/images/payment_icons/unionpay.svg +0 -1
- data/app/assets/images/payment_icons/unzerbanktransfer.svg +0 -1
- data/app/assets/images/payment_icons/upi.svg +0 -1
- data/app/assets/images/payment_icons/usbank.svg +0 -1
- data/app/assets/images/payment_icons/usdc.svg +0 -1
- data/app/assets/images/payment_icons/usdt.svg +0 -1
- data/app/assets/images/payment_icons/venmo.svg +0 -1
- data/app/assets/images/payment_icons/vipps.svg +0 -1
- data/app/assets/images/payment_icons/visa.svg +0 -1
- data/app/assets/images/payment_icons/volksbank.svg +0 -1
- data/app/assets/images/payment_icons/waavepaybybank.svg +0 -1
- data/app/assets/images/payment_icons/walley.svg +0 -1
- data/app/assets/images/payment_icons/wbtc.svg +0 -1
- data/app/assets/images/payment_icons/wechatpay.svg +0 -1
- data/app/assets/images/payment_icons/whishcheckout.svg +0 -1
- data/app/assets/images/payment_icons/wingbank.svg +0 -1
- data/app/assets/images/payment_icons/xrp.svg +0 -1
- data/app/assets/images/payment_icons/zip.svg +0 -1
- data/app/controllers/spree/base_controller.rb +0 -11
- data/app/finders/concerns/spree/product_filterable.rb +0 -9
- data/app/finders/spree/addresses/find.rb +0 -27
- data/app/finders/spree/base_finder.rb +0 -14
- data/app/finders/spree/countries/find.rb +0 -31
- data/app/finders/spree/credit_cards/find.rb +0 -12
- data/app/finders/spree/option_values/find_available.rb +0 -28
- data/app/finders/spree/orders/find_complete.rb +0 -114
- data/app/finders/spree/orders/find_current.rb +0 -24
- data/app/finders/spree/orders/finder_helper.rb +0 -17
- data/app/finders/spree/products/find.rb +0 -328
- data/app/finders/spree/taxons/find.rb +0 -99
- data/app/finders/spree/variants/find.rb +0 -30
- data/app/finders/spree/variants/option_types_finder.rb +0 -21
- data/app/helpers/spree/addresses_helper.rb +0 -97
- data/app/helpers/spree/base_helper.rb +0 -132
- data/app/helpers/spree/currency_helper.rb +0 -46
- data/app/helpers/spree/integrations_helper.rb +0 -15
- data/app/helpers/spree/locale_helper.rb +0 -44
- data/app/helpers/spree/localized_names_helper.rb +0 -25
- data/app/helpers/spree/products_helper.rb +0 -147
- data/app/helpers/spree/shipment_helper.rb +0 -12
- data/app/javascript/spree/core/controllers/address_autocomplete_controller.js +0 -230
- data/app/javascript/spree/core/controllers/address_form_controller.js +0 -98
- data/app/javascript/spree/core/controllers/disable_submit_button_controller.js +0 -19
- data/app/javascript/spree/core/controllers/enable_button_controller.js +0 -29
- data/app/javascript/spree/core/helpers/address_autocomplete/google_places_suggestions_provider.js +0 -161
- data/app/javascript/spree/core/helpers/debounce.js +0 -9
- data/app/javascript/spree/core/helpers/scroll_lock.js +0 -25
- data/app/jobs/spree/media/migrate_product_assets_job.rb +0 -83
- data/app/jobs/spree/reports/generate_job.rb +0 -23
- data/app/mailers/spree/report_mailer.rb +0 -20
- data/app/models/concerns/spree/adjustment_source.rb +0 -58
- data/app/models/concerns/spree/default_price.rb +0 -138
- data/app/models/concerns/spree/display_on.rb +0 -50
- data/app/models/concerns/spree/image_methods.rb +0 -40
- data/app/models/concerns/spree/legacy_multi_store_support.rb +0 -48
- data/app/models/concerns/spree/metafield_filterable.rb +0 -162
- data/app/models/concerns/spree/metafields.rb +0 -256
- data/app/models/concerns/spree/number_as_param.rb +0 -13
- data/app/models/concerns/spree/store_scoped_resource.rb +0 -37
- data/app/models/concerns/spree/unique_name.rb +0 -12
- data/app/models/spree/adjustable/adjuster/base.rb +0 -25
- data/app/models/spree/adjustable/adjuster/promotion.rb +0 -41
- data/app/models/spree/adjustable/adjuster/tax.rb +0 -26
- data/app/models/spree/adjustable/adjustments_updater.rb +0 -74
- data/app/models/spree/adjustable/promotion_accumulator.rb +0 -78
- data/app/models/spree/adjustment.rb +0 -130
- data/app/models/spree/asset/support/active_storage.rb +0 -26
- data/app/models/spree/calculator/default_tax.rb +0 -87
- data/app/models/spree/calculator/returns/default_refund_amount.rb +0 -40
- data/app/models/spree/checkout/default_requirements.rb +0 -51
- data/app/models/spree/checkout/registry.rb +0 -112
- data/app/models/spree/checkout/requirement.rb +0 -49
- data/app/models/spree/checkout/requirements.rb +0 -56
- data/app/models/spree/checkout/step.rb +0 -52
- data/app/models/spree/customer_return.rb +0 -94
- data/app/models/spree/image/configuration/active_storage.rb +0 -11
- data/app/models/spree/image.rb +0 -6
- data/app/models/spree/legacy_admin_user.rb +0 -31
- data/app/models/spree/legacy_user.rb +0 -33
- data/app/models/spree/log_entry.rb +0 -30
- data/app/models/spree/metafield_definition/search_capabilities.rb +0 -104
- data/app/models/spree/metafields/boolean.rb +0 -15
- data/app/models/spree/metafields/json.rb +0 -37
- data/app/models/spree/metafields/long_text.rb +0 -11
- data/app/models/spree/metafields/number.rb +0 -23
- data/app/models/spree/metafields/rich_text.rb +0 -18
- data/app/models/spree/metafields/short_text.rb +0 -15
- data/app/models/spree/option_type_prototype.rb +0 -9
- data/app/models/spree/order/address_book.rb +0 -100
- data/app/models/spree/order/checkout.rb +0 -350
- data/app/models/spree/order/currency_updater.rb +0 -37
- data/app/models/spree/order/digital.rb +0 -60
- data/app/models/spree/order/gift_card.rb +0 -71
- data/app/models/spree/order/payments.rb +0 -64
- data/app/models/spree/order/store_credit.rb +0 -110
- data/app/models/spree/order/webhooks.rb +0 -19
- data/app/models/spree/order_approval.rb +0 -19
- data/app/models/spree/order_cancellation.rb +0 -19
- data/app/models/spree/order_contents.rb +0 -31
- data/app/models/spree/order_routing/strategy/legacy.rb +0 -33
- data/app/models/spree/payment/webhooks.rb +0 -15
- data/app/models/spree/permission_sets/base.rb +0 -81
- data/app/models/spree/permission_sets/configuration_management.rb +0 -64
- data/app/models/spree/permission_sets/dashboard_display.rb +0 -17
- data/app/models/spree/permission_sets/default_customer.rb +0 -83
- data/app/models/spree/permission_sets/order_display.rb +0 -27
- data/app/models/spree/permission_sets/order_management.rb +0 -33
- data/app/models/spree/permission_sets/product_display.rb +0 -27
- data/app/models/spree/permission_sets/product_management.rb +0 -28
- data/app/models/spree/permission_sets/promotion_management.rb +0 -22
- data/app/models/spree/permission_sets/role_management.rb +0 -21
- data/app/models/spree/permission_sets/stock_display.rb +0 -19
- data/app/models/spree/permission_sets/stock_management.rb +0 -19
- data/app/models/spree/permission_sets/super_user.rb +0 -28
- data/app/models/spree/permission_sets/user_display.rb +0 -19
- data/app/models/spree/permission_sets/user_management.rb +0 -20
- data/app/models/spree/product/webhooks.rb +0 -17
- data/app/models/spree/prototype_taxon.rb +0 -9
- data/app/models/spree/reimbursement/credit.rb +0 -27
- data/app/models/spree/reimbursement/reimbursement_type_engine.rb +0 -44
- data/app/models/spree/reimbursement/reimbursement_type_validator.rb +0 -15
- data/app/models/spree/reimbursement.rb +0 -167
- data/app/models/spree/reimbursement_performer.rb +0 -34
- data/app/models/spree/reimbursement_tax_calculator.rb +0 -37
- data/app/models/spree/reimbursement_type/credit.rb +0 -13
- data/app/models/spree/reimbursement_type/exchange.rb +0 -9
- data/app/models/spree/reimbursement_type/original_payment.rb +0 -13
- data/app/models/spree/reimbursement_type/reimbursement_helpers.rb +0 -64
- data/app/models/spree/reimbursement_type/store_credit.rb +0 -20
- data/app/models/spree/reimbursement_type.rb +0 -22
- data/app/models/spree/report.rb +0 -140
- data/app/models/spree/report_line_item.rb +0 -27
- data/app/models/spree/report_line_items/products_performance.rb +0 -76
- data/app/models/spree/report_line_items/sales_total.rb +0 -49
- data/app/models/spree/reports/products_performance.rb +0 -44
- data/app/models/spree/reports/sales_total.rb +0 -18
- data/app/models/spree/return_authorization.rb +0 -109
- data/app/models/spree/return_item/eligibility_validator/base_validator.rb +0 -24
- data/app/models/spree/return_item/eligibility_validator/default.rb +0 -30
- data/app/models/spree/return_item/eligibility_validator/inventory_shipped.rb +0 -16
- data/app/models/spree/return_item/eligibility_validator/no_reimbursements.rb +0 -16
- data/app/models/spree/return_item/eligibility_validator/order_completed.rb +0 -16
- data/app/models/spree/return_item/eligibility_validator/rma_required.rb +0 -16
- data/app/models/spree/return_item/eligibility_validator/time_since_purchase.rb +0 -16
- data/app/models/spree/return_item/exchange_variant_eligibility/same_option_value.rb +0 -34
- data/app/models/spree/return_item/exchange_variant_eligibility/same_product.rb +0 -9
- data/app/models/spree/return_item.rb +0 -287
- data/app/models/spree/returns_calculator.rb +0 -7
- data/app/models/spree/search_provider/meilisearch.rb +0 -551
- data/app/models/spree/shipment/custom_events.rb +0 -47
- data/app/models/spree/shipment/webhooks.rb +0 -11
- data/app/models/spree/shipment_handler.rb +0 -38
- data/app/models/spree/shipping_category.rb +0 -25
- data/app/models/spree/shipping_method_category.rb +0 -8
- data/app/models/spree/shipping_method_zone.rb +0 -8
- data/app/models/spree/state_change.rb +0 -12
- data/app/models/spree/stock/splitter/digital.rb +0 -35
- data/app/models/spree/stock/splitter/shipping_category.rb +0 -31
- data/app/models/spree/stock_item/webhooks.rb +0 -6
- data/app/models/spree/stock_movement/webhooks.rb +0 -6
- data/app/models/spree/variant/webhooks.rb +0 -6
- data/app/presenters/spree/csv/metafields_helper.rb +0 -17
- data/app/presenters/spree/search_provider/product_presenter.rb +0 -158
- data/app/presenters/spree/variant_presenter.rb +0 -81
- data/app/presenters/spree/variants/option_types_presenter.rb +0 -87
- data/app/services/spree/account/addresses/create.rb +0 -8
- data/app/services/spree/account/addresses/update.rb +0 -8
- data/app/services/spree/account/create.rb +0 -17
- data/app/services/spree/account/update.rb +0 -15
- data/app/services/spree/cart/add_item.rb +0 -63
- data/app/services/spree/cart/associate.rb +0 -29
- data/app/services/spree/cart/change_currency.rb +0 -27
- data/app/services/spree/cart/create.rb +0 -26
- data/app/services/spree/cart/destroy.rb +0 -50
- data/app/services/spree/cart/empty.rb +0 -38
- data/app/services/spree/cart/estimate_shipping_rates.rb +0 -39
- data/app/services/spree/cart/recalculate.rb +0 -35
- data/app/services/spree/cart/remove_item.rb +0 -39
- data/app/services/spree/cart/remove_line_item.rb +0 -28
- data/app/services/spree/cart/remove_out_of_stock_items.rb +0 -65
- data/app/services/spree/cart/set_quantity.rb +0 -32
- data/app/services/spree/cart/update.rb +0 -37
- data/app/services/spree/carts/complete.rb +0 -50
- data/app/services/spree/carts/upsert_items.rb +0 -76
- data/app/services/spree/checkout/complete.rb +0 -23
- data/app/services/spree/checkout/get_shipping_rates.rb +0 -52
- data/app/services/spree/checkout/next.rb +0 -13
- data/app/services/spree/checkout/select_shipping_method.rb +0 -63
- data/app/services/spree/checkout/update.rb +0 -72
- data/app/services/spree/credit_cards/destroy.rb +0 -25
- data/app/services/spree/fulfillments/create.rb +0 -259
- data/app/services/spree/gift_cards/apply.rb +0 -78
- data/app/services/spree/gift_cards/redeem.rb +0 -17
- data/app/services/spree/gift_cards/remove.rb +0 -39
- data/app/services/spree/line_items/create.rb +0 -20
- data/app/services/spree/line_items/destroy.rb +0 -18
- data/app/services/spree/line_items/helper.rb +0 -11
- data/app/services/spree/line_items/update.rb +0 -17
- data/app/services/spree/orders/build_shipments.rb +0 -29
- data/app/services/spree/orders/cancel.rb +0 -54
- data/app/services/spree/orders/complete.rb +0 -53
- data/app/services/spree/orders/update_contact_information.rb +0 -19
- data/app/services/spree/orders/upsert_items.rb +0 -70
- data/app/services/spree/payments/handle_webhook.rb +0 -57
- data/app/services/spree/search_provider/metafield_schema.rb +0 -144
- data/app/services/spree/seeds/countries.rb +0 -35
- data/app/services/spree/seeds/default_reimbursement_types.rb +0 -12
- data/app/services/spree/seeds/shipping_categories.rb +0 -12
- data/app/services/spree/seeds/states.rb +0 -82
- data/app/services/spree/seeds/stock_locations.rb +0 -18
- data/app/services/spree/seeds/store_credit_categories.rb +0 -14
- data/app/services/spree/seeds/zones.rb +0 -52
- data/app/services/spree/shipments/add_item.rb +0 -32
- data/app/services/spree/shipments/change_state.rb +0 -14
- data/app/services/spree/shipments/create.rb +0 -48
- data/app/services/spree/shipments/helper.rb +0 -23
- data/app/services/spree/shipments/remove_item.rb +0 -55
- data/app/services/spree/stores/settings_defaults_by_country.rb +0 -38
- data/app/services/spree/themes/duplicator.rb +0 -40
- data/app/sorters/spree/base_sorter.rb +0 -47
- data/app/sorters/spree/classifications/sort.rb +0 -68
- data/app/sorters/spree/products/sort.rb +0 -73
- data/app/subscribers/spree/report_subscriber.rb +0 -26
- data/app/views/spree/addresses/_form.html.erb +0 -59
- data/app/views/spree/addresses/_suggestions_box.erb +0 -14
- data/app/views/spree/admin_user_mailer/confirmation_email.html.erb +0 -7
- data/app/views/spree/report_mailer/report_done.html.erb +0 -7
- data/app/views/spree/shared/_google_places_api_loader.html.erb +0 -7
- data/app/views/spree/shared/_mailer_line_item.html.erb +0 -12
- data/app/views/spree/shared/_payment.html.erb +0 -52
- data/config/importmap.rb +0 -15
- data/config/initializers/carmen.rb +0 -23
- data/config/initializers/rails61_fixes.rb +0 -1
- data/db/migrate/20250120152208_add_default_locale_to_action_text_rich_texts.rb +0 -7
- data/db/migrate/20250122113708_add_first_and_last_name_to_spree_admin_class.rb +0 -9
- data/db/migrate/20250204162453_create_spree_reports.rb +0 -13
- data/db/migrate/20250217171018_create_action_text_video_embeds.rb +0 -11
- data/db/migrate/20250508060800_add_selected_locale_to_spree_admin_users.rb +0 -8
- data/db/migrate/20260429000001_create_spree_order_cancellations.rb +0 -25
- data/db/migrate/20260429000002_create_spree_order_approvals.rb +0 -22
- data/db/sample_data/markets.rb +0 -64
- data/db/sample_data/metafield_definitions.rb +0 -7
- data/db/sample_data/shipping_methods.rb +0 -61
- data/lib/generators/spree/authentication/custom/custom_generator.rb +0 -49
- data/lib/generators/spree/authentication/custom/templates/authentication_helpers.rb.tt +0 -50
- data/lib/generators/spree/authentication/devise/devise_generator.rb +0 -84
- data/lib/generators/spree/authentication/devise/templates/authentication_helpers.rb.tt +0 -50
- data/lib/generators/spree/dummy/templates/app/assets/config/manifest.js +0 -0
- data/lib/spree/core/components.rb +0 -31
- data/lib/spree/core/controller_helpers/auth.rb +0 -52
- data/lib/spree/core/controller_helpers/currency.rb +0 -59
- data/lib/spree/core/controller_helpers/locale.rb +0 -99
- data/lib/spree/core/controller_helpers/order.rb +0 -172
- data/lib/spree/core/controller_helpers/strong_parameters.rb +0 -48
- data/lib/spree/core/controller_helpers/turbo.rb +0 -19
- data/lib/spree/core/partials.rb +0 -42
- data/lib/spree/core/previews/report_preview.rb +0 -40
- data/lib/spree/permitted_attributes.rb +0 -337
- data/lib/spree/testing_support/authorization_helpers.rb +0 -72
- data/lib/spree/testing_support/caching.rb +0 -47
- data/lib/spree/testing_support/capybara_config.rb +0 -45
- data/lib/spree/testing_support/capybara_ext.rb +0 -83
- data/lib/spree/testing_support/controller_requests.rb +0 -11
- data/lib/spree/testing_support/factories/adjustment_factory.rb +0 -28
- data/lib/spree/testing_support/factories/asset_factory.rb +0 -12
- data/lib/spree/testing_support/factories/customer_return_factory.rb +0 -36
- data/lib/spree/testing_support/factories/digital_factory.rb +0 -10
- data/lib/spree/testing_support/factories/image_factory.rb +0 -11
- data/lib/spree/testing_support/factories/inventory_unit_factory.rb +0 -18
- data/lib/spree/testing_support/factories/log_entry_factory.rb +0 -6
- data/lib/spree/testing_support/factories/metafield_definition_factory.rb +0 -82
- data/lib/spree/testing_support/factories/metafield_factory.rb +0 -68
- data/lib/spree/testing_support/factories/prototype_factory.rb +0 -9
- data/lib/spree/testing_support/factories/reimbursement_credit_factory.rb +0 -7
- data/lib/spree/testing_support/factories/reimbursement_factory.rb +0 -16
- data/lib/spree/testing_support/factories/reimbursement_type_factory.rb +0 -7
- data/lib/spree/testing_support/factories/report_factory.rb +0 -33
- data/lib/spree/testing_support/factories/return_authorization_factory.rb +0 -21
- data/lib/spree/testing_support/factories/return_item_factory.rb +0 -14
- data/lib/spree/testing_support/factories/shipment_factory.rb +0 -21
- data/lib/spree/testing_support/factories/shipping_category_factory.rb +0 -9
- data/lib/spree/testing_support/factories/shipping_method_factory.rb +0 -31
- data/lib/spree/testing_support/factories/shipping_rate_factory.rb +0 -7
- data/lib/spree/testing_support/factories/state_change_factory.rb +0 -8
- data/lib/spree/testing_support/factories/stock_item_factory.rb +0 -22
- data/lib/spree/testing_support/factories/store_credit_category_factory.rb +0 -9
- data/lib/spree/testing_support/factories/store_credit_type_factory.rb +0 -16
- data/lib/spree/testing_support/factories/wished_variant_factory.rb +0 -6
- data/lib/spree/webhooks.rb +0 -22
- data/lib/tasks/role_users.rake +0 -21
- data/vendor/javascript/@rails--request.js.js +0 -4
- data/vendor/javascript/@stimulus-components--auto-submit.js +0 -4
- data/vendor/javascript/stimulus-reveal-controller.js +0 -4
- data/vendor/javascript/stimulus-textarea-autogrow.js +0 -4
- data/vendor/javascript/tailwindcss-stimulus-components.js +0 -4
data/app/models/spree/product.rb
CHANGED
|
@@ -4,22 +4,18 @@
|
|
|
4
4
|
# Products properties include description, permalink, availability,
|
|
5
5
|
# shipping category, etc. that do not change by variant.
|
|
6
6
|
#
|
|
7
|
-
# MASTER VARIANT
|
|
8
|
-
# Every product has one master variant, which stores master price and sku, size and weight, etc.
|
|
9
|
-
# The master variant does not have option values associated with it.
|
|
10
|
-
# Price, SKU, size, weight, etc. are all delegated to the master variant.
|
|
11
|
-
# Contains on_hand inventory levels only when there are no variants for the product.
|
|
12
|
-
#
|
|
13
7
|
# VARIANTS
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
8
|
+
# Every product has at least one variant. Simple products have a single variant
|
|
9
|
+
# with no option values; products with options have one variant per combination.
|
|
10
|
+
# `default_variant` is the "face" of the product — price, SKU, size, weight, etc.
|
|
11
|
+
# are delegated to it. Inventory units are tied to Variant; the sum of each
|
|
12
|
+
# variant's on_hand determines the product's "on_hand" level.
|
|
19
13
|
#
|
|
20
14
|
|
|
21
15
|
module Spree
|
|
22
16
|
class Product < Spree.base_class
|
|
17
|
+
include Spree::CSV::CustomFieldsHelper
|
|
18
|
+
|
|
23
19
|
has_prefix_id :prod # Stripe: prod_
|
|
24
20
|
|
|
25
21
|
acts_as_paranoid
|
|
@@ -30,40 +26,52 @@ module Spree
|
|
|
30
26
|
include Spree::ProductScopes
|
|
31
27
|
include Spree::TranslatableResource
|
|
32
28
|
include Spree::MemoizedData
|
|
33
|
-
include Spree::
|
|
34
|
-
include Spree::
|
|
29
|
+
include Spree::SanitizableRichText
|
|
30
|
+
include Spree::HasCustomFields
|
|
31
|
+
include Spree::CustomFieldFilterable
|
|
35
32
|
include Spree::Metadata
|
|
33
|
+
include Spree::HasExternalReferences
|
|
36
34
|
include Spree::Searchable
|
|
37
|
-
include Spree::Product::Webhooks
|
|
38
35
|
include Spree::Product::Slugs
|
|
39
36
|
include Spree::Product::Channels
|
|
40
|
-
include Spree::LegacyMultiStoreSupport unless defined?(SpreeMultiStore)
|
|
41
37
|
include Spree::SearchIndexable
|
|
42
|
-
|
|
43
|
-
include Spree::VendorConcern
|
|
44
|
-
end
|
|
38
|
+
include Spree::StorePreferences
|
|
45
39
|
|
|
46
40
|
publishes_lifecycle_events
|
|
47
41
|
|
|
48
|
-
MEMOIZED_METHODS = %w[total_on_hand
|
|
42
|
+
MEMOIZED_METHODS = %w[total_on_hand category_and_ancestors
|
|
49
43
|
default_variant_id tax_category default_variant variant_for_images
|
|
50
|
-
|
|
44
|
+
primary_category buy_box_variants resolved_delivery_profile
|
|
51
45
|
purchasable? in_stock? backorderable? digital?]
|
|
52
46
|
|
|
47
|
+
# Statuses an operator sets directly. `bulk_status_update` validates
|
|
48
|
+
# against this, which is why the review statuses are not in it: reaching
|
|
49
|
+
# `proposed` is a seller submitting and reaching `rejected` is an operator
|
|
50
|
+
# deciding, and neither is a value to assign in bulk.
|
|
53
51
|
STATUSES = %w[draft active archived].freeze
|
|
54
52
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
# Where a product sits in the marketplace review lifecycle. Only the
|
|
54
|
+
# workflows (Products::Propose, ::Approve, ::Reject) move a product in or
|
|
55
|
+
# out of these; see docs/plans/6.0-seller-product-submission.md.
|
|
56
|
+
REVIEW_STATUSES = %w[proposed rejected].freeze
|
|
57
|
+
|
|
58
|
+
ALL_STATUSES = (STATUSES + REVIEW_STATUSES).freeze
|
|
60
59
|
|
|
61
60
|
TRANSLATABLE_FIELDS = %i[name description slug meta_description meta_title].freeze
|
|
62
61
|
RICH_TEXT_TRANSLATABLE_FIELDS = %i[description].freeze
|
|
63
62
|
translates(*TRANSLATABLE_FIELDS, column_fallback: Spree.mobility_column_fallback)
|
|
64
63
|
|
|
64
|
+
has_spree_rich_text :description
|
|
65
|
+
|
|
66
|
+
# Translated descriptions live on the Mobility translation table, so writes
|
|
67
|
+
# through locale accessors or +upsert_translations+ never touch the base
|
|
68
|
+
# record's +description+ attribute — the translation model needs its own
|
|
69
|
+
# sanitization pass.
|
|
65
70
|
self::Translation.class_eval do
|
|
71
|
+
include Spree::SanitizableRichText
|
|
72
|
+
|
|
66
73
|
normalizes :name, :meta_title, with: ->(value) { value&.to_s&.squish&.presence }
|
|
74
|
+
sanitizes_rich_text :description
|
|
67
75
|
end
|
|
68
76
|
|
|
69
77
|
# we need to have this callback before any dependent: :destroy associations
|
|
@@ -72,10 +80,76 @@ module Spree
|
|
|
72
80
|
|
|
73
81
|
has_many :product_option_types, -> { order(:position) }, dependent: :destroy, inverse_of: :product
|
|
74
82
|
has_many :option_types, through: :product_option_types
|
|
75
|
-
has_many :
|
|
76
|
-
has_many :
|
|
77
|
-
has_many :
|
|
78
|
-
|
|
83
|
+
has_many :product_categories, -> { order(created_at: :asc) }, class_name: 'Spree::ProductCategory', dependent: :delete_all, inverse_of: :product
|
|
84
|
+
has_many :categories, through: :product_categories, class_name: 'Spree::Category', source: :category, before_remove: :remove_category
|
|
85
|
+
has_many :taxonomies, through: :categories, deprecated: true
|
|
86
|
+
|
|
87
|
+
# @deprecated The classification_count column was renamed to categories_count in 6.0.
|
|
88
|
+
alias_attribute :classification_count, :categories_count
|
|
89
|
+
|
|
90
|
+
# @deprecated Use #product_categories; removed in 6.1.
|
|
91
|
+
# The live row in the review trail, or nil for a product nobody submitted.
|
|
92
|
+
#
|
|
93
|
+
# @return [Spree::ProductSubmission, nil]
|
|
94
|
+
def latest_submission
|
|
95
|
+
submissions.latest_first.first
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Why the marketplace turned this listing down, for the seller to read.
|
|
99
|
+
# Answers nil once the product moves on, so a stale note never shows
|
|
100
|
+
# against a product that is no longer rejected.
|
|
101
|
+
#
|
|
102
|
+
# @return [String, nil]
|
|
103
|
+
def rejection_reason
|
|
104
|
+
return unless rejected?
|
|
105
|
+
|
|
106
|
+
latest_submission&.review_note
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Whether this product is waiting on, or has had, a marketplace decision.
|
|
110
|
+
#
|
|
111
|
+
# @return [Boolean]
|
|
112
|
+
def in_review?
|
|
113
|
+
REVIEW_STATUSES.include?(status)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def classifications
|
|
117
|
+
Spree::Deprecation.warn('Spree::Product#classifications is deprecated and will be removed in Spree 6.1. Use #product_categories instead.')
|
|
118
|
+
product_categories
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# @deprecated Use #categories / #category_ids; removed in 6.1.
|
|
122
|
+
def taxons
|
|
123
|
+
Spree::Deprecation.warn('Spree::Product#taxons is deprecated and will be removed in Spree 6.1. Use #categories instead.')
|
|
124
|
+
categories
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def taxons=(value)
|
|
128
|
+
Spree::Deprecation.warn('Spree::Product#taxons= is deprecated and will be removed in Spree 6.1. Use #categories= instead.')
|
|
129
|
+
self.categories = value
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def taxon_ids
|
|
133
|
+
Spree::Deprecation.warn('Spree::Product#taxon_ids is deprecated and will be removed in Spree 6.1. Use #category_ids instead.')
|
|
134
|
+
category_ids
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def taxon_ids=(ids)
|
|
138
|
+
Spree::Deprecation.warn('Spree::Product#taxon_ids= is deprecated and will be removed in Spree 6.1. Use #category_ids= instead.')
|
|
139
|
+
self.category_ids = ids
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
has_many :product_collections, class_name: 'Spree::ProductCollection', dependent: :destroy_async, inverse_of: :product
|
|
143
|
+
has_many :collections, through: :product_collections
|
|
144
|
+
has_many :catalog_products, class_name: 'Spree::CatalogProduct', dependent: :destroy_async, inverse_of: :product
|
|
145
|
+
has_many :catalogs, through: :catalog_products
|
|
146
|
+
|
|
147
|
+
# Dropped with the product so a deleted product stops excluding itself from
|
|
148
|
+
# delivery methods. Destroyed inline rather than async — a product sits in
|
|
149
|
+
# at most a handful of exclusion rules, and deferring it would leave the
|
|
150
|
+
# rule reporting an id the API can no longer resolve.
|
|
151
|
+
has_many :delivery_method_rule_products, class_name: 'Spree::DeliveryMethodRuleProduct',
|
|
152
|
+
dependent: :destroy, inverse_of: :product
|
|
79
153
|
|
|
80
154
|
has_many :product_promotion_rules, class_name: 'Spree::ProductPromotionRule'
|
|
81
155
|
has_many :promotion_rules, through: :product_promotion_rules, class_name: 'Spree::PromotionRule'
|
|
@@ -86,65 +160,92 @@ module Spree
|
|
|
86
160
|
class_name: 'Spree::Promotion',
|
|
87
161
|
source: :promotion
|
|
88
162
|
|
|
89
|
-
belongs_to :tax_category, class_name: 'Spree::TaxCategory'
|
|
90
|
-
belongs_to :
|
|
91
|
-
|
|
163
|
+
belongs_to :tax_category, class_name: 'Spree::TaxCategory', optional: true
|
|
164
|
+
belongs_to :product_type, class_name: 'Spree::ProductType', optional: true, counter_cache: :products_count
|
|
165
|
+
# The seller this product belongs to on a marketplace. Nil is the
|
|
166
|
+
# operator's own catalog — which is everything, on a store selling only
|
|
167
|
+
# its own goods.
|
|
168
|
+
belongs_to :seller, class_name: 'Spree::Seller', optional: true, inverse_of: :products
|
|
169
|
+
|
|
170
|
+
# How this product ships: origins, zones and methods all hang off the
|
|
171
|
+
# profile. Required — a product without one could not be fulfilled at
|
|
172
|
+
# all — and auto-assigned on create (type template, else the store's
|
|
173
|
+
# default profile), so callers never have to think about it. The FK is
|
|
174
|
+
# the renamed 5.x shipping_category_id, so migrated catalogs arrive
|
|
175
|
+
# already assigned.
|
|
176
|
+
belongs_to :delivery_profile, class_name: 'Spree::DeliveryProfile', inverse_of: :products
|
|
177
|
+
|
|
178
|
+
# Every one of the product's variants now resolves its profile through
|
|
179
|
+
# +resolved_delivery_profile+, which memoizes — so a reassignment has to
|
|
180
|
+
# drop the memo, or the whole fleet keeps shipping on the old profile
|
|
181
|
+
# until the product is saved.
|
|
182
|
+
%i[delivery_profile delivery_profile_id].each do |name|
|
|
183
|
+
define_method(:"#{name}=") do |value|
|
|
184
|
+
@resolved_delivery_profile = nil
|
|
185
|
+
@digital = nil
|
|
186
|
+
super(value)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
92
189
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
190
|
+
# Guards every write path (including raw prefixed-id assignment) against
|
|
191
|
+
# linking another store's profile.
|
|
192
|
+
validate :delivery_profile_must_belong_to_store, if: :delivery_profile_id_changed?
|
|
193
|
+
# Either side moving breaks the pair, and a product's store is not frozen
|
|
194
|
+
# after create, so watching only the seller would let a move carry the old
|
|
195
|
+
# store's seller along.
|
|
196
|
+
validate :seller_must_belong_to_store, if: -> { seller_id_changed? || store_id_changed? }
|
|
97
197
|
|
|
198
|
+
# Every product has at least one variant. `default_variant` is the "face" of
|
|
199
|
+
# the product (price display, default add-to-cart, property delegation).
|
|
98
200
|
has_many :variants,
|
|
99
|
-
-> { where(is_master: false).order(:position) },
|
|
100
|
-
inverse_of: :product,
|
|
101
|
-
class_name: 'Spree::Variant'
|
|
102
|
-
|
|
103
|
-
has_many :variants_including_master,
|
|
104
201
|
-> { order(:position) },
|
|
105
202
|
inverse_of: :product,
|
|
106
203
|
class_name: 'Spree::Variant',
|
|
107
204
|
dependent: :destroy
|
|
108
205
|
|
|
109
|
-
|
|
206
|
+
belongs_to :default_variant, class_name: 'Spree::Variant', optional: true, autosave: true
|
|
207
|
+
|
|
208
|
+
has_many :prices, through: :variants
|
|
110
209
|
|
|
111
|
-
has_many :
|
|
210
|
+
has_many :stock_levels, through: :variants
|
|
112
211
|
|
|
113
|
-
has_many :line_items, through: :
|
|
212
|
+
has_many :line_items, through: :variants
|
|
114
213
|
has_many :orders, through: :line_items
|
|
115
214
|
has_many :completed_orders, -> { reorder(nil).distinct.complete }, through: :line_items, source: :order
|
|
116
215
|
|
|
117
|
-
has_many :media, -> { order(:position) }, as: :viewable, dependent: :destroy, class_name: 'Spree::
|
|
216
|
+
has_many :media, -> { order(:position) }, as: :viewable, dependent: :destroy, class_name: 'Spree::Media'
|
|
118
217
|
|
|
119
|
-
|
|
120
|
-
|
|
218
|
+
# The review trail for a seller's listing. Append-only: the latest row is
|
|
219
|
+
# the live one (docs/plans/6.0-seller-product-submission.md).
|
|
220
|
+
has_many :submissions, class_name: 'Spree::ProductSubmission', dependent: :destroy, inverse_of: :product
|
|
121
221
|
|
|
122
|
-
|
|
222
|
+
has_many :variant_images, -> { order(:position) }, source: :images, through: :variants
|
|
223
|
+
|
|
224
|
+
belongs_to :primary_media, class_name: 'Spree::Media', optional: true, foreign_key: :primary_media_id
|
|
123
225
|
|
|
124
226
|
has_many :option_value_variants, class_name: 'Spree::OptionValueVariant', through: :variants
|
|
125
227
|
has_many :option_values, class_name: 'Spree::OptionValue', through: :variants
|
|
126
228
|
|
|
127
|
-
has_many :
|
|
128
|
-
|
|
129
|
-
has_many :digitals, through: :variants_including_master
|
|
229
|
+
has_many :digital_assets, through: :variants, class_name: 'Spree::DigitalAsset'
|
|
230
|
+
has_many :digitals, through: :variants, class_name: 'Spree::DigitalAsset', source: :digital_assets, deprecated: true
|
|
130
231
|
|
|
131
|
-
after_initialize :ensure_master
|
|
132
232
|
after_initialize :assign_default_tax_category
|
|
233
|
+
# The type's profile is a creation-time template: stamped here, never
|
|
234
|
+
# synced afterwards — reassigning the type later leaves the product's
|
|
235
|
+
# profile alone. Falls back to the store's default profile, keeping the
|
|
236
|
+
# required association satisfiable without the caller naming one.
|
|
237
|
+
before_validation :stamp_template_delivery_profile, on: :create
|
|
133
238
|
|
|
134
|
-
|
|
135
|
-
|
|
239
|
+
after_create :sync_associations_from_product_type
|
|
240
|
+
after_update :sync_associations_from_product_type, if: :saved_change_to_product_type_id?
|
|
241
|
+
after_create :ensure_default_variant
|
|
242
|
+
after_create :set_default_variant
|
|
136
243
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
after_save :apply_pending_media, if: :pending_media?
|
|
244
|
+
after_save :auto_promote_default_variant
|
|
245
|
+
after_save :run_touch_callbacks, if: :saved_changes?
|
|
246
|
+
after_touch :touch_categories
|
|
141
247
|
|
|
142
|
-
|
|
143
|
-
after_save :run_touch_callbacks, if: :anything_changed?
|
|
144
|
-
after_save :reset_nested_changes
|
|
145
|
-
after_touch :touch_taxons
|
|
146
|
-
|
|
147
|
-
after_commit :auto_match_taxons, if: :eligible_for_taxon_matching?
|
|
248
|
+
after_commit :auto_match_collections, if: :eligible_for_collection_matching?
|
|
148
249
|
|
|
149
250
|
with_options length: { maximum: 255 }, allow_blank: true do
|
|
150
251
|
validates :meta_keywords
|
|
@@ -152,44 +253,53 @@ module Spree
|
|
|
152
253
|
end
|
|
153
254
|
with_options presence: true do
|
|
154
255
|
validates :name
|
|
155
|
-
validates :shipping_category, if: :requires_shipping_category?
|
|
156
|
-
validates :price, if: :requires_price?
|
|
157
256
|
end
|
|
158
257
|
|
|
258
|
+
# Every persisted product must keep a default variant. It's assigned on
|
|
259
|
+
# create by +set_default_variant+, so only enforce it on update.
|
|
260
|
+
validates :default_variant, presence: true, on: :update
|
|
261
|
+
|
|
159
262
|
validate :discontinue_on_must_be_later_than_make_active_at, if: -> { make_active_at && discontinue_on }
|
|
160
263
|
|
|
161
264
|
scope :for_store, ->(store) { where(store_id: store.id) }
|
|
162
|
-
|
|
163
|
-
|
|
265
|
+
# Products belonging to the given seller. Passing nil selects the
|
|
266
|
+
# operator's own catalog, which on a store with no sellers is everything.
|
|
267
|
+
# The same answer `Seller#products` gives, as a scope a bulk read can chain.
|
|
268
|
+
scope :for_seller, ->(seller) { where(seller_id: seller.respond_to?(:id) ? seller.id : seller) }
|
|
164
269
|
scope :not_archived, -> { where.not(status: 'archived') }
|
|
165
270
|
scope :on_sale, lambda { |currency = nil|
|
|
166
271
|
currency ||= Spree::Store.default.default_currency
|
|
167
|
-
|
|
272
|
+
with_currency(currency).
|
|
273
|
+
where.not(spree_prices: { amount: 0 }).
|
|
168
274
|
where.not(spree_prices: { compare_at_amount: [nil, 0] }).
|
|
169
275
|
where("#{Spree::Price.table_name}.compare_at_amount > #{Spree::Price.table_name}.amount")
|
|
170
276
|
}
|
|
171
277
|
|
|
172
|
-
|
|
278
|
+
# @param store [Spree::Store] whose custom-field definitions take part in
|
|
279
|
+
# the search. Definitions are store-owned, so the caller says which store
|
|
280
|
+
# is searching; `Spree::Current.store` is the request's answer and a
|
|
281
|
+
# background caller (an export, say) passes its own.
|
|
282
|
+
scope :search, ->(query, store = Spree::Current.store) {
|
|
173
283
|
next none if query.blank?
|
|
174
284
|
|
|
175
285
|
product_ids = Spree::Variant.search_by_product_name_or_sku(query).pluck(:product_id)
|
|
176
286
|
|
|
177
|
-
searchable_definitions =
|
|
287
|
+
searchable_definitions = store.custom_field_definitions.
|
|
178
288
|
for_resource_type('Spree::Product').
|
|
179
289
|
searchable
|
|
180
290
|
|
|
181
|
-
# Only pay for the
|
|
182
|
-
# the leading-wildcard LIKE over
|
|
183
|
-
|
|
184
|
-
joins(
|
|
291
|
+
# Only pay for the custom_field scan when some definition opts into search;
|
|
292
|
+
# the leading-wildcard LIKE over spree_custom_fields can't use an index.
|
|
293
|
+
custom_field_ids = if searchable_definitions.exists?
|
|
294
|
+
joins(custom_fields: :custom_field_definition).
|
|
185
295
|
merge(searchable_definitions).
|
|
186
|
-
where(search_condition(Spree::
|
|
296
|
+
where(search_condition(Spree::CustomField, :value, query)).
|
|
187
297
|
unscope(:order).distinct.pluck(:id)
|
|
188
298
|
else
|
|
189
299
|
[]
|
|
190
300
|
end
|
|
191
301
|
|
|
192
|
-
where(id: (product_ids +
|
|
302
|
+
where(id: (product_ids + custom_field_ids).uniq.compact)
|
|
193
303
|
}
|
|
194
304
|
|
|
195
305
|
# Backward compatibility alias — remove in Spree 6.0
|
|
@@ -197,19 +307,15 @@ module Spree
|
|
|
197
307
|
|
|
198
308
|
scope :archivable, -> { where(status: %w[active draft]) }
|
|
199
309
|
scope :by_source, ->(source) { send(source) }
|
|
200
|
-
scope :paused, -> { where(status: 'paused') }
|
|
201
310
|
scope :published, -> { where(status: 'active') }
|
|
202
311
|
|
|
203
|
-
attr_accessor :option_values_hash
|
|
204
|
-
|
|
205
312
|
accepts_nested_attributes_for(
|
|
206
313
|
:variants,
|
|
207
314
|
allow_destroy: true,
|
|
208
315
|
reject_if: lambda do |v|
|
|
209
|
-
v[:option_value_variants_attributes].blank? && v[:
|
|
316
|
+
v[:option_value_variants_attributes].blank? && v[:stock_levels_attributes].blank? && v[:prices_attributes].blank?
|
|
210
317
|
end
|
|
211
318
|
)
|
|
212
|
-
accepts_nested_attributes_for :master, reject_if: :all_blank
|
|
213
319
|
accepts_nested_attributes_for(
|
|
214
320
|
:product_option_types,
|
|
215
321
|
allow_destroy: true,
|
|
@@ -224,178 +330,202 @@ module Spree
|
|
|
224
330
|
self.tag_list = tags
|
|
225
331
|
end
|
|
226
332
|
|
|
227
|
-
# Sets prices on the
|
|
333
|
+
# Sets prices on the default variant.
|
|
228
334
|
# Accepts array of { currency:, amount:, compare_at_amount: } hashes.
|
|
229
335
|
def prices=(prices_params)
|
|
230
|
-
|
|
336
|
+
find_or_build_default_variant.prices = prices_params
|
|
231
337
|
end
|
|
232
338
|
|
|
233
|
-
#
|
|
234
|
-
#
|
|
235
|
-
#
|
|
236
|
-
#
|
|
339
|
+
# Accepts both prefixed IDs and raw integer IDs. Only categories belonging to
|
|
340
|
+
# the product's own store are assigned — ids from another store are dropped,
|
|
341
|
+
# preventing cross-store category attachment. Decodes prefixed IDs, then calls
|
|
342
|
+
# the generated setter via super.
|
|
237
343
|
def category_ids=(ids)
|
|
238
344
|
decoded_ids = Array(ids).filter_map do |id|
|
|
239
|
-
id.to_s.include?('_') ? Spree::
|
|
345
|
+
id.to_s.include?('_') ? Spree::Category.decode_prefixed_id(id) : id
|
|
240
346
|
end
|
|
241
|
-
|
|
347
|
+
super(Spree::Category.for_store(assignable_store).where(id: decoded_ids).ids)
|
|
242
348
|
end
|
|
243
349
|
|
|
244
|
-
#
|
|
245
|
-
#
|
|
246
|
-
#
|
|
247
|
-
# the dedicated DELETE /media endpoint to avoid accidental data loss when
|
|
248
|
-
# a form ships stale state).
|
|
350
|
+
# Accepts both prefixed IDs and raw integer IDs. Only collections belonging
|
|
351
|
+
# to the product's own store are assigned; this overrides the generated
|
|
352
|
+
# setter and calls super.
|
|
249
353
|
#
|
|
250
|
-
#
|
|
251
|
-
#
|
|
252
|
-
#
|
|
253
|
-
#
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
return super if media_params.first.is_a?(Spree::Asset)
|
|
261
|
-
|
|
262
|
-
if new_record?
|
|
263
|
-
@pending_media_params = media_params
|
|
264
|
-
return
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
apply_media(media_params)
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
# Syncs variants from an array of hashes.
|
|
271
|
-
# Creates new variants, updates existing ones (matched by :id), and removes unlisted ones.
|
|
272
|
-
# Must be called on a persisted product (use after_save or call explicitly after create).
|
|
273
|
-
# @param variants_params [Array<Hash>] array of variant attribute hashes
|
|
274
|
-
# @return [void]
|
|
275
|
-
def variants=(variants_params)
|
|
276
|
-
return super if variants_params.blank? || variants_params.first.is_a?(Spree::Variant)
|
|
277
|
-
|
|
278
|
-
# Store for deferred processing if product is not yet persisted
|
|
279
|
-
if new_record?
|
|
280
|
-
@pending_variants_params = variants_params
|
|
281
|
-
return
|
|
354
|
+
# This is a replace setter, so it governs manual membership only. Automatic
|
|
355
|
+
# collections are materialized from their rules, which means they must
|
|
356
|
+
# survive a write that doesn't mention them (otherwise saving a product
|
|
357
|
+
# would wipe rule-derived membership until the next regeneration) and must
|
|
358
|
+
# not be assignable by hand (a hand-set member would vanish at that
|
|
359
|
+
# regeneration). So incoming automatic ids are ignored, and the product's
|
|
360
|
+
# existing automatic memberships are carried over untouched.
|
|
361
|
+
def collection_ids=(ids)
|
|
362
|
+
decoded_ids = Array(ids).filter_map do |id|
|
|
363
|
+
id.to_s.include?('_') ? Spree::Collection.decode_prefixed_id(id) : id
|
|
282
364
|
end
|
|
283
|
-
|
|
284
|
-
|
|
365
|
+
manual_ids = Spree::Collection.for_store(assignable_store).manual.where(id: decoded_ids).ids
|
|
366
|
+
super(manual_ids | collections.automatic.ids)
|
|
285
367
|
end
|
|
286
368
|
|
|
287
|
-
self.whitelisted_ransackable_attributes = %w[description name slug discontinue_on status available_on created_at updated_at]
|
|
288
|
-
self.whitelisted_ransackable_associations = %w[
|
|
289
|
-
|
|
290
|
-
self.whitelisted_ransackable_scopes = %w[not_discontinued search_by_name in_taxon in_category in_categories price_between
|
|
369
|
+
self.whitelisted_ransackable_attributes = %w[description name slug discontinue_on status available_on created_at updated_at seller_id]
|
|
370
|
+
self.whitelisted_ransackable_associations = %w[categories collections store channels variants default_variant tags labels
|
|
371
|
+
product_type product_categories option_types seller]
|
|
372
|
+
self.whitelisted_ransackable_scopes = %w[not_discontinued search_by_name in_taxon in_category in_categories in_collection price_between
|
|
291
373
|
price_lte price_gte
|
|
292
374
|
search multi_search in_stock out_of_stock with_option_value_ids
|
|
293
375
|
|
|
294
376
|
ascend_by_price descend_by_price]
|
|
295
377
|
|
|
378
|
+
# All product-level convenience attributes delegate to the default variant —
|
|
379
|
+
# one target, no branching. Reads resolve the existing default variant
|
|
380
|
+
# (nil-safe) and never build one as a side effect; only setters build on
|
|
381
|
+
# demand, so `product.sku = ...` still works before the product is persisted.
|
|
296
382
|
[
|
|
297
|
-
:sku, :barcode, :weight, :height, :width, :depth, :
|
|
383
|
+
:sku, :barcode, :weight, :height, :width, :depth, :dimensions_unit, :weight_unit,
|
|
384
|
+
:price_in, :amount_in, :compare_at_amount_in,
|
|
385
|
+
:cost_currency, :cost_price, :track_inventory
|
|
298
386
|
].each do |method_name|
|
|
299
|
-
delegate method_name, :
|
|
387
|
+
delegate method_name, to: :default_variant, allow_nil: true
|
|
388
|
+
delegate :"#{method_name}=", to: :find_or_build_default_variant
|
|
300
389
|
end
|
|
301
390
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
391
|
+
# Read-only delegations: these have no product-level writer. Prices are
|
|
392
|
+
# written per currency through the default variant's +set_price+.
|
|
393
|
+
delegate :compare_at_price, :track_inventory?, :images, to: :default_variant, allow_nil: true
|
|
394
|
+
|
|
395
|
+
# No state machine — status moves through the Spree::Products workflows
|
|
396
|
+
# (docs/plans/6.0-service-workflows.md). has_status generates the `draft`
|
|
397
|
+
# and `archived` scopes and every predicate, but never redefines what the
|
|
398
|
+
# model already owns: `Product.active` stays the currency-aware scope from
|
|
399
|
+
# Spree::ProductScopes rather than a plain status lookup.
|
|
400
|
+
include Spree::HasStatus
|
|
401
|
+
has_status(*ALL_STATUSES, default: :draft)
|
|
402
|
+
|
|
403
|
+
# @deprecated Call Spree.product_activate_workflow — removed in 6.1.
|
|
404
|
+
def activate!
|
|
405
|
+
Spree::Deprecation.warn('Spree::Product#activate! is deprecated and will be removed in Spree 6.1. Call Spree.product_activate_workflow instead.')
|
|
406
|
+
run_status_workflow(Spree.product_activate_workflow)
|
|
307
407
|
end
|
|
308
408
|
|
|
309
|
-
|
|
310
|
-
|
|
409
|
+
# @deprecated Call Spree.product_archive_workflow — removed in 6.1.
|
|
410
|
+
def archive!
|
|
411
|
+
Spree::Deprecation.warn('Spree::Product#archive! is deprecated and will be removed in Spree 6.1. Call Spree.product_archive_workflow instead.')
|
|
412
|
+
run_status_workflow(Spree.product_archive_workflow)
|
|
413
|
+
end
|
|
311
414
|
|
|
312
|
-
#
|
|
313
|
-
|
|
415
|
+
# @deprecated Call Spree.product_draft_workflow — removed in 6.1.
|
|
416
|
+
def draft!
|
|
417
|
+
Spree::Deprecation.warn('Spree::Product#draft! is deprecated and will be removed in Spree 6.1. Call Spree.product_draft_workflow instead.')
|
|
418
|
+
run_status_workflow(Spree.product_draft_workflow)
|
|
419
|
+
end
|
|
314
420
|
|
|
315
|
-
|
|
421
|
+
def self.bulk_auto_match_collections(store, product_ids)
|
|
422
|
+
return if store.collections.automatic.none?
|
|
316
423
|
|
|
317
|
-
|
|
318
|
-
event :activate do
|
|
319
|
-
transition to: :active
|
|
320
|
-
end
|
|
321
|
-
after_transition to: :active, do: [:after_activate, :send_product_activated_webhook, :publish_product_activated_event]
|
|
424
|
+
products_to_auto_match_ids = store.products.not_deleted.not_archived.where(id: product_ids).ids
|
|
322
425
|
|
|
323
|
-
|
|
324
|
-
|
|
426
|
+
auto_match_collections_jobs = products_to_auto_match_ids.map do |product_id|
|
|
427
|
+
Spree::Products::AutoMatchCollectionsJob.new(product_id).tap { |job| job.scheduled_at = 30.seconds.from_now }
|
|
325
428
|
end
|
|
326
|
-
after_transition to: :archived, do: [:after_archive, :send_product_archived_webhook, :publish_product_archived_event]
|
|
327
429
|
|
|
328
|
-
|
|
329
|
-
transition to: :draft
|
|
330
|
-
end
|
|
331
|
-
after_transition to: :draft, do: [:after_draft, :send_product_drafted_webhook]
|
|
430
|
+
ActiveJob.perform_all_later(auto_match_collections_jobs)
|
|
332
431
|
end
|
|
333
432
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
433
|
+
# The variant this product leads with: its price, its stock, and what the
|
|
434
|
+
# add-to-cart button buys. On a product only the operator sells this is
|
|
435
|
+
# simply the cheapest available variant; once sellers share the listing it
|
|
436
|
+
# is whichever of their offers wins the buy box.
|
|
437
|
+
#
|
|
438
|
+
# Computed per read and never stored — it turns on price, stock and who is
|
|
439
|
+
# currently selling, none of which hold still
|
|
440
|
+
# (docs/plans/6.0-multi-vendor-marketplace.md, Decision 11).
|
|
441
|
+
#
|
|
442
|
+
# @param currency [String, nil]
|
|
443
|
+
# @param option_value_ids [Array<String, Integer>, nil] narrows to one option
|
|
444
|
+
# combination, so a `Condition` option gives a new buy box and a used one
|
|
445
|
+
# @return [Spree::Variant, nil]
|
|
446
|
+
def buy_box_variant(currency: nil, option_value_ids: nil)
|
|
447
|
+
currency ||= Spree::Current.currency
|
|
448
|
+
key = [currency, option_value_ids]
|
|
449
|
+
@buy_box_variants ||= {}
|
|
450
|
+
return @buy_box_variants[key] if @buy_box_variants.key?(key)
|
|
338
451
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
452
|
+
@buy_box_variants[key] = Spree::Dependencies.product_buy_box_service.constantize.call(
|
|
453
|
+
product: self, currency: currency, option_value_ids: option_value_ids
|
|
454
|
+
).value
|
|
455
|
+
end
|
|
342
456
|
|
|
343
|
-
|
|
457
|
+
# The variant this product leads with in a currency: the buy-box winner,
|
|
458
|
+
# else the default. One definition, because a caller that prices a page and
|
|
459
|
+
# a caller that preloads for it must land on the same variant — otherwise
|
|
460
|
+
# the preload misses and every row falls back to a query of its own.
|
|
461
|
+
#
|
|
462
|
+
# @param currency [String, nil]
|
|
463
|
+
# @return [Spree::Variant, nil]
|
|
464
|
+
def featured_variant(currency: nil)
|
|
465
|
+
buy_box_variant(currency: currency) || default_variant
|
|
344
466
|
end
|
|
345
467
|
|
|
346
|
-
#
|
|
468
|
+
# Availability asks whether *anyone who is selling today* has this on the
|
|
469
|
+
# shelf. It deliberately does not ask the buy box: the winner is picked
|
|
470
|
+
# by price in one currency, and stock is a fact about the shelf, not about
|
|
471
|
+
# pricing — a variant stocked but priced only in another currency is still
|
|
472
|
+
# in stock. What it does share with the buy box is the seller test: a
|
|
473
|
+
# variant from a seller who is suspended, still onboarding or away is not
|
|
474
|
+
# for sale, so it cannot make the product available.
|
|
347
475
|
def purchasable?
|
|
348
|
-
@purchasable
|
|
476
|
+
return @purchasable unless @purchasable.nil?
|
|
477
|
+
|
|
478
|
+
@purchasable = sellable_variants.any?(&:purchasable?)
|
|
349
479
|
end
|
|
350
480
|
|
|
351
|
-
# Can't use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259
|
|
352
481
|
def in_stock?
|
|
353
|
-
@in_stock
|
|
354
|
-
end
|
|
482
|
+
return @in_stock unless @in_stock.nil?
|
|
355
483
|
|
|
356
|
-
|
|
357
|
-
def backorderable?
|
|
358
|
-
default_variant.backorderable? || variants.any?(&:backorderable?)
|
|
484
|
+
@in_stock = sellable_variants.any?(&:in_stock?)
|
|
359
485
|
end
|
|
360
486
|
|
|
361
|
-
def
|
|
362
|
-
|
|
487
|
+
def backorderable?
|
|
488
|
+
sellable_variants.any?(&:backorderable?)
|
|
363
489
|
end
|
|
364
490
|
|
|
365
|
-
|
|
366
|
-
|
|
491
|
+
# The variants a shopper could actually buy from: every one whose seller
|
|
492
|
+
# is selling today, first-party included. Reads the loaded association so
|
|
493
|
+
# a serialized list resolves it from variants it already holds.
|
|
494
|
+
#
|
|
495
|
+
# @return [Array<Spree::Variant>]
|
|
496
|
+
def sellable_variants
|
|
497
|
+
variants.select do |variant|
|
|
498
|
+
seller = variant.resolved_seller
|
|
499
|
+
seller.nil? || seller.sellable?
|
|
500
|
+
end
|
|
367
501
|
end
|
|
368
502
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
# @return [Boolean]
|
|
372
|
-
def has_variants?
|
|
373
|
-
return variants.size.positive? if variants.loaded?
|
|
374
|
-
|
|
375
|
-
variant_count.positive?
|
|
503
|
+
def on_sale?(currency)
|
|
504
|
+
prices.find_all { |p| p.currency == currency && p.non_zero? }.any?(&:discounted?)
|
|
376
505
|
end
|
|
377
506
|
|
|
378
|
-
#
|
|
379
|
-
#
|
|
380
|
-
#
|
|
381
|
-
# by `position` attribute
|
|
382
|
-
# If `track_inventory_levels` is disabled it will return first Variant sorted
|
|
383
|
-
# by `position` attribute
|
|
384
|
-
#
|
|
507
|
+
# The default variant is a persisted FK, but before the product is saved (or
|
|
508
|
+
# if it somehow has no default set) fall back to the first variant —
|
|
509
|
+
# including one built in memory via the delegated setters.
|
|
385
510
|
# @return [Spree::Variant]
|
|
386
511
|
def default_variant
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
512
|
+
super || variants.first
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
def find_or_build_default_variant
|
|
516
|
+
default_variant || variants.build
|
|
392
517
|
end
|
|
393
518
|
|
|
394
|
-
#
|
|
395
|
-
#
|
|
396
|
-
|
|
397
|
-
|
|
519
|
+
# "Does this product have more than one variant (i.e. options to choose from)?"
|
|
520
|
+
# Uses the variant_count counter cache for performance.
|
|
521
|
+
# @return [Boolean]
|
|
522
|
+
def has_multiple_variants?
|
|
523
|
+
return variants.size > 1 if variants.loaded?
|
|
524
|
+
|
|
525
|
+
variant_count > 1
|
|
398
526
|
end
|
|
527
|
+
# @deprecated Use #has_multiple_variants? — will be removed in Spree 6.1.
|
|
528
|
+
alias has_variants? has_multiple_variants?
|
|
399
529
|
|
|
400
530
|
# Returns the product's media gallery.
|
|
401
531
|
# Uses product-level media if present, otherwise falls back to variant images.
|
|
@@ -419,34 +549,19 @@ module Spree
|
|
|
419
549
|
alias has_variant_images? has_media?
|
|
420
550
|
|
|
421
551
|
# Returns the variant that should be used for displaying images.
|
|
422
|
-
# Priority:
|
|
552
|
+
# Priority: default_variant > first variant with images
|
|
423
553
|
# @return [Spree::Variant, nil]
|
|
424
554
|
def variant_for_images
|
|
425
555
|
@variant_for_images ||= find_variant_for_images
|
|
426
556
|
end
|
|
427
557
|
|
|
428
|
-
# @deprecated
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
end
|
|
433
|
-
|
|
434
|
-
# @deprecated Use #primary_media instead.
|
|
435
|
-
def featured_image
|
|
436
|
-
Spree::Deprecation.warn('Spree::Product#featured_image is deprecated and will be removed in Spree 6.0. Please use Spree::Product#primary_media instead.')
|
|
437
|
-
primary_media
|
|
438
|
-
end
|
|
439
|
-
|
|
440
|
-
# @deprecated Use #primary_media instead.
|
|
441
|
-
def primary_image
|
|
442
|
-
Spree::Deprecation.warn('Spree::Product#primary_image is deprecated and will be removed in Spree 6.0. Please use Spree::Product#primary_media instead.')
|
|
443
|
-
primary_media
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
# Returns secondary media for Product (for hover effects).
|
|
447
|
-
# @return [Spree::Asset, nil]
|
|
558
|
+
# @deprecated Read #gallery_media directly; removed in 6.1. Nothing in
|
|
559
|
+
# Spree calls this — a hover image is a storefront presentation choice,
|
|
560
|
+
# not something core should name.
|
|
561
|
+
# @return [Spree::Media, nil]
|
|
448
562
|
def secondary_image
|
|
449
|
-
|
|
563
|
+
Spree::Deprecation.warn('Spree::Product#secondary_image is deprecated and will be removed in Spree 6.1. Use #gallery_media instead.')
|
|
564
|
+
gallery_media.second
|
|
450
565
|
end
|
|
451
566
|
|
|
452
567
|
# @deprecated Use media_count instead
|
|
@@ -458,7 +573,14 @@ module Spree
|
|
|
458
573
|
# Checks product-level media first, then falls back to variant images.
|
|
459
574
|
# Called when media is added, removed, or reordered.
|
|
460
575
|
def update_thumbnail!
|
|
461
|
-
|
|
576
|
+
# Fresh scopes, never the cached associations — this runs from a media
|
|
577
|
+
# row's after_commit, where a loaded association is missing its siblings.
|
|
578
|
+
candidates = media.reload.order(:position).presence || variant_images.reload.order(:position)
|
|
579
|
+
# Only media that can draw as an image: `thumbnail_url` is rendered in an
|
|
580
|
+
# <img> everywhere it's used, so a video with no still leaves no
|
|
581
|
+
# thumbnail at all rather than a broken one.
|
|
582
|
+
first_media = candidates.find(&:renderable_as_image?)
|
|
583
|
+
|
|
462
584
|
update_column(:primary_media_id, first_media&.id)
|
|
463
585
|
end
|
|
464
586
|
|
|
@@ -479,12 +601,9 @@ module Spree
|
|
|
479
601
|
# Returns tax category for Product
|
|
480
602
|
# @return [Spree::TaxCategory, nil]
|
|
481
603
|
def tax_category
|
|
482
|
-
@tax_category ||= super || TaxCategory.default
|
|
604
|
+
@tax_category ||= super || TaxCategory.default(assignable_store)
|
|
483
605
|
end
|
|
484
606
|
|
|
485
|
-
# Adding properties and option types on creation based on a chosen prototype
|
|
486
|
-
attr_accessor :prototype_id
|
|
487
|
-
|
|
488
607
|
def first_or_default_variant(currency)
|
|
489
608
|
if !has_variants?
|
|
490
609
|
default_variant
|
|
@@ -495,38 +614,50 @@ module Spree
|
|
|
495
614
|
end
|
|
496
615
|
end
|
|
497
616
|
|
|
617
|
+
# The first variant a shopper can actually buy, in this currency.
|
|
618
|
+
#
|
|
619
|
+
# Position order, deliberately — this is "the first one that works", not
|
|
620
|
+
# the buy box's ranked winner. What it does borrow from the buy box is the
|
|
621
|
+
# seller check: a variant from a seller who is suspended, still onboarding
|
|
622
|
+
# or away is not for sale, so it cannot be what the product displays.
|
|
498
623
|
def first_available_variant(currency)
|
|
499
|
-
|
|
624
|
+
sellable_variants.find do |variant|
|
|
625
|
+
variant.purchasable? && variant.price_in(currency).amount.present?
|
|
626
|
+
end
|
|
500
627
|
end
|
|
501
628
|
|
|
629
|
+
# Whether the shop price differs between this product's variants. Reads
|
|
630
|
+
# base prices only: a price list's rows are what one audience pays under an
|
|
631
|
+
# agreement, and a ladder holds several rows for one variant, so counting
|
|
632
|
+
# them would report a product as varying when it does not
|
|
633
|
+
# (docs/plans/6.0-volume-pricing.md).
|
|
502
634
|
def price_varies?(currency)
|
|
503
|
-
|
|
635
|
+
shop_prices(currency).map(&:amount).uniq.count > 1
|
|
504
636
|
end
|
|
505
637
|
|
|
506
638
|
def any_variant_available?(currency)
|
|
507
|
-
|
|
508
|
-
first_available_variant(currency).present?
|
|
509
|
-
else
|
|
510
|
-
master.purchasable? && master.price_in(currency).amount.present?
|
|
511
|
-
end
|
|
639
|
+
first_available_variant(currency).present?
|
|
512
640
|
end
|
|
513
641
|
|
|
514
642
|
# returns the lowest price for the product in the given currency
|
|
515
|
-
#
|
|
643
|
+
# prices are usually already loaded, so this should not trigger an extra query
|
|
516
644
|
def lowest_price(currency)
|
|
517
|
-
|
|
645
|
+
shop_prices(currency).min_by(&:amount)
|
|
518
646
|
end
|
|
519
647
|
|
|
520
|
-
#
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
648
|
+
# The prices this product is offered at publicly — one per variant. A price
|
|
649
|
+
# list's rows are excluded: they are what one audience pays under an
|
|
650
|
+
# agreement, so surfacing the cheapest of them as the product's "from"
|
|
651
|
+
# price would quote every shopper a contract they are not party to.
|
|
652
|
+
#
|
|
653
|
+
# Filtered in memory rather than through a scope because callers have
|
|
654
|
+
# already loaded the association, and a scope would re-query per product
|
|
655
|
+
# in a listing.
|
|
656
|
+
#
|
|
657
|
+
# @param currency [String]
|
|
658
|
+
# @return [Array<Spree::Price>]
|
|
659
|
+
def shop_prices(currency)
|
|
660
|
+
prices.find_all { |p| p.currency == currency && p.price_list_id.nil? && p.non_zero? }
|
|
530
661
|
end
|
|
531
662
|
|
|
532
663
|
# for adding products which are closely related to existing ones
|
|
@@ -572,21 +703,14 @@ module Spree
|
|
|
572
703
|
!!discontinue_on && discontinue_on <= Time.current
|
|
573
704
|
end
|
|
574
705
|
|
|
575
|
-
# determine if any variant
|
|
706
|
+
# determine if any variant can be supplied
|
|
576
707
|
def can_supply?
|
|
577
|
-
|
|
708
|
+
variants.any?(&:can_supply?)
|
|
578
709
|
end
|
|
579
710
|
|
|
580
|
-
# determine if any variant
|
|
711
|
+
# determine if any variant is out of stock and backorderable
|
|
581
712
|
def backordered?
|
|
582
|
-
|
|
583
|
-
end
|
|
584
|
-
|
|
585
|
-
def self.like_any(fields, values)
|
|
586
|
-
conditions = fields.product(values).map do |(field, value)|
|
|
587
|
-
arel_table[field].matches("%#{value}%")
|
|
588
|
-
end
|
|
589
|
-
where conditions.inject(:or)
|
|
713
|
+
variants.any?(&:backordered?)
|
|
590
714
|
end
|
|
591
715
|
|
|
592
716
|
# Suitable for displaying only variants that has at least one option value.
|
|
@@ -602,78 +726,91 @@ module Spree
|
|
|
602
726
|
@total_on_hand ||= if any_variants_not_track_inventory?
|
|
603
727
|
BigDecimal::INFINITY
|
|
604
728
|
else
|
|
605
|
-
if
|
|
606
|
-
|
|
729
|
+
if variants.loaded?
|
|
730
|
+
variants.sum(&:total_on_hand)
|
|
607
731
|
else
|
|
608
|
-
|
|
732
|
+
stock_levels.loaded? ? stock_levels.sum(&:available_count) : stock_levels.sum('count_on_hand - allocated_count')
|
|
609
733
|
end
|
|
610
734
|
end
|
|
611
735
|
end
|
|
612
736
|
|
|
613
|
-
#
|
|
614
|
-
|
|
615
|
-
|
|
737
|
+
# @deprecated Use {#stock_levels}; removed in 6.1.
|
|
738
|
+
def stock_items
|
|
739
|
+
Spree::Deprecation.warn('Spree::Product#stock_items is deprecated and will be removed in Spree 6.1. Use #stock_levels instead.')
|
|
740
|
+
stock_levels
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
# @deprecated Use #default_variant — the master variant is being removed in Spree 6.1.
|
|
616
744
|
def master
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
# Returns the brand taxon for the product
|
|
621
|
-
# @return [Spree::Taxon]
|
|
622
|
-
def brand_taxon
|
|
623
|
-
@brand_taxon ||= if classification_count.zero?
|
|
624
|
-
nil
|
|
625
|
-
elsif Spree.use_translations?
|
|
626
|
-
taxons.joins(:taxonomy).
|
|
627
|
-
join_translation_table(Taxonomy).
|
|
628
|
-
find_by(Taxonomy.translation_table_alias => { name: Spree.t(:taxonomy_brands_name) })
|
|
629
|
-
elsif taxons.loaded?
|
|
630
|
-
taxons.find { |taxon| taxon.taxonomy.name == Spree.t(:taxonomy_brands_name) }
|
|
631
|
-
else
|
|
632
|
-
taxons.joins(:taxonomy).find_by(Taxonomy.table_name => { name: Spree.t(:taxonomy_brands_name) })
|
|
633
|
-
end
|
|
634
|
-
end
|
|
635
|
-
|
|
636
|
-
# Returns the brand name for the product
|
|
637
|
-
# @return [String]
|
|
638
|
-
def brand_name
|
|
639
|
-
brand_taxon&.name
|
|
745
|
+
Spree::Deprecation.warn('Spree::Product#master is deprecated and will be removed in Spree 6.1. Use #default_variant instead.')
|
|
746
|
+
default_variant
|
|
640
747
|
end
|
|
641
748
|
|
|
642
|
-
|
|
643
|
-
|
|
749
|
+
# @deprecated Use #variants — will be removed in Spree 6.1.
|
|
750
|
+
def variants_including_master
|
|
751
|
+
Spree::Deprecation.warn('Spree::Product#variants_including_master is deprecated and will be removed in Spree 6.1. Use #variants instead.')
|
|
752
|
+
variants
|
|
753
|
+
end
|
|
644
754
|
|
|
645
|
-
|
|
755
|
+
# @deprecated Use #default_variant_id — will be removed in Spree 6.1.
|
|
756
|
+
def master_id
|
|
757
|
+
default_variant_id
|
|
646
758
|
end
|
|
647
759
|
|
|
648
|
-
|
|
649
|
-
|
|
760
|
+
# The product's primary category — the first manually-assigned category.
|
|
761
|
+
# Renamed from #main_taxon in 6.0.
|
|
762
|
+
def primary_category
|
|
763
|
+
return if categories_count.zero?
|
|
764
|
+
|
|
765
|
+
@primary_category ||= categories.first
|
|
766
|
+
end
|
|
650
767
|
|
|
651
|
-
|
|
768
|
+
# @deprecated Use {#primary_category}.
|
|
769
|
+
def main_taxon
|
|
770
|
+
Spree::Deprecation.warn('Spree::Product#main_taxon is deprecated and will be removed in Spree 6.1. Use #primary_category instead.')
|
|
771
|
+
primary_category
|
|
652
772
|
end
|
|
653
773
|
|
|
654
774
|
def any_variant_in_stock_or_backorderable?
|
|
655
775
|
if has_variants?
|
|
656
|
-
|
|
776
|
+
variants.in_stock_or_backorderable.not_discontinued.exists?
|
|
657
777
|
else
|
|
658
|
-
|
|
778
|
+
default_variant.in_stock_or_backorderable?
|
|
659
779
|
end
|
|
660
780
|
end
|
|
661
781
|
|
|
662
782
|
# Check if the product is digital by checking if any of its shipping methods are digital delivery
|
|
663
783
|
# This is used to determine if the product is digital and should have a digital delivery price
|
|
664
|
-
# instead of a physical shipping price
|
|
784
|
+
# instead of a physical shipping price. The profile kind declares it —
|
|
785
|
+
# capabilities are never stated twice.
|
|
665
786
|
#
|
|
666
787
|
# @return [Boolean]
|
|
667
788
|
def digital?
|
|
668
|
-
|
|
789
|
+
# Memoized via nil-check: MemoizedData resets caches by assigning nil.
|
|
790
|
+
return @digital unless @digital.nil?
|
|
791
|
+
|
|
792
|
+
@digital = !!resolved_delivery_profile&.digital?
|
|
669
793
|
end
|
|
670
794
|
|
|
671
|
-
|
|
795
|
+
# The profile that governs this product. The association is required for
|
|
796
|
+
# new records; the store-default fallback covers rows predating the
|
|
797
|
+
# backfill (never expected in practice, cheap to be safe about).
|
|
798
|
+
#
|
|
799
|
+
# @return [Spree::DeliveryProfile, nil]
|
|
800
|
+
def resolved_delivery_profile
|
|
801
|
+
# Memoized via nil-check, like +digital?+ above: the store-default branch
|
|
802
|
+
# is an uncached lookup, and every variant on the product asks.
|
|
803
|
+
return @resolved_delivery_profile unless @resolved_delivery_profile.nil?
|
|
804
|
+
|
|
805
|
+
@resolved_delivery_profile = delivery_profile || (store && Spree::DeliveryProfile.default_for(store))
|
|
806
|
+
end
|
|
807
|
+
|
|
808
|
+
def auto_match_collections
|
|
672
809
|
return if deleted?
|
|
673
810
|
return if archived?
|
|
674
|
-
return if store.nil? || store.
|
|
811
|
+
return if store.nil? || store.collections.automatic.none?
|
|
675
812
|
|
|
676
|
-
Spree::Products::
|
|
813
|
+
Spree::Products::AutoMatchCollectionsJob.set(wait: 30.seconds).perform_later(id)
|
|
677
814
|
end
|
|
678
815
|
|
|
679
816
|
def to_csv(store = nil)
|
|
@@ -688,21 +825,22 @@ module Spree
|
|
|
688
825
|
else
|
|
689
826
|
[]
|
|
690
827
|
end
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
828
|
+
# Through the shared helper so the value row is built from exactly the
|
|
829
|
+
# definitions, in exactly the order, that Export#custom_fields_headers
|
|
830
|
+
# used for the header row — a mismatch shifts every value column.
|
|
831
|
+
custom_field_values = custom_fields_for_csv(self, store)
|
|
832
|
+
categories_for_csv ||= categories.reorder(depth: :desc).first(3).pluck(:pretty_name)
|
|
833
|
+
categories_for_csv.fill(nil, categories_for_csv.size...3)
|
|
696
834
|
|
|
697
835
|
csv_lines = []
|
|
698
|
-
all_variants =
|
|
836
|
+
all_variants = variants.to_a
|
|
699
837
|
default_currency = store.default_currency
|
|
700
838
|
additional_currencies = store.supported_currencies_list.map(&:iso_code) - [default_currency]
|
|
701
839
|
|
|
702
840
|
# Primary rows in the store's default currency
|
|
703
841
|
all_variants.each_with_index do |variant, index|
|
|
704
|
-
csv_lines << Spree::CSV::ProductVariantPresenter.new(self, variant, index, properties_for_csv,
|
|
705
|
-
|
|
842
|
+
csv_lines << Spree::CSV::ProductVariantPresenter.new(self, variant, index, properties_for_csv, categories_for_csv, store,
|
|
843
|
+
custom_field_values).call
|
|
706
844
|
end
|
|
707
845
|
|
|
708
846
|
# Price-only rows for each additional currency
|
|
@@ -732,257 +870,118 @@ module Spree
|
|
|
732
870
|
private
|
|
733
871
|
|
|
734
872
|
# Determines which variant should be used for displaying media.
|
|
735
|
-
# Priority:
|
|
873
|
+
# Priority: default_variant > first variant with media
|
|
736
874
|
def find_variant_for_images
|
|
737
|
-
return
|
|
738
|
-
return default_variant if has_variants? && default_variant.has_media?
|
|
875
|
+
return default_variant if default_variant&.has_media?
|
|
739
876
|
return find_variant_with_images if has_media?
|
|
740
877
|
|
|
741
878
|
nil
|
|
742
879
|
end
|
|
743
880
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
@pending_variants_params = nil
|
|
753
|
-
end
|
|
754
|
-
|
|
755
|
-
def pending_media?
|
|
756
|
-
@pending_media_params.present?
|
|
757
|
-
end
|
|
881
|
+
# Additive, unlike the legacy prototype callback which replaced both sets —
|
|
882
|
+
# the type seeds the product when attached (creation, later assignment,
|
|
883
|
+
# reassignment) and never removes anything; detaching seeds nothing.
|
|
884
|
+
# The already-linked sets come from the join tables in one query each: the
|
|
885
|
+
# cached associations can be stale here (pending variants insert option-type
|
|
886
|
+
# joins through product_option_types within the same save).
|
|
887
|
+
def sync_associations_from_product_type
|
|
888
|
+
return unless product_type
|
|
758
889
|
|
|
759
|
-
|
|
760
|
-
|
|
890
|
+
missing_option_type_ids = product_type.option_type_ids - product_option_types.pluck(:option_type_id)
|
|
891
|
+
Spree::OptionType.where(id: missing_option_type_ids).each { |option_type| option_types << option_type }
|
|
761
892
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
# Eager-load Asset descendants once so the type allowlist is stable across
|
|
768
|
-
# the loop (and across requests once subclasses are referenced). Computed
|
|
769
|
-
# per-call rather than at class-load to avoid forcing autoload of every
|
|
770
|
-
# Asset subclass during boot.
|
|
771
|
-
allowed_types = [Spree::Asset, *Spree::Asset.descendants].map(&:name).to_set
|
|
772
|
-
media_params.each do |raw|
|
|
773
|
-
attrs = raw.respond_to?(:to_h) ? raw.to_h : raw
|
|
774
|
-
attrs = attrs.with_indifferent_access
|
|
775
|
-
|
|
776
|
-
# Upsert path: entries with an `id` patch an existing asset (alt,
|
|
777
|
-
# position, variant_ids). Entries with a `signed_id` create+attach.
|
|
778
|
-
# Omitting an entry leaves it alone — explicit DELETE on the dedicated
|
|
779
|
-
# media endpoint is still the only way to remove an asset.
|
|
780
|
-
asset_id = attrs.delete(:id)
|
|
781
|
-
if asset_id.present?
|
|
782
|
-
asset = media.find_by_param(asset_id) || next
|
|
783
|
-
asset.update!(attrs.except(:signed_id, :type))
|
|
784
|
-
next
|
|
785
|
-
end
|
|
786
|
-
|
|
787
|
-
signed_id = attrs.delete(:signed_id)
|
|
788
|
-
next if signed_id.blank?
|
|
789
|
-
|
|
790
|
-
media_type = attrs.delete(:type) || 'Spree::Image'
|
|
791
|
-
next unless allowed_types.include?(media_type)
|
|
792
|
-
|
|
793
|
-
asset = media.build(attrs.except(:id))
|
|
794
|
-
asset.type = media_type
|
|
795
|
-
asset.attachment.attach(signed_id)
|
|
796
|
-
asset.save!
|
|
797
|
-
end
|
|
798
|
-
end
|
|
799
|
-
|
|
800
|
-
def apply_variants(variants_params)
|
|
801
|
-
variant_ids_in_payload = []
|
|
802
|
-
master_touched = false
|
|
803
|
-
mutated = false
|
|
804
|
-
|
|
805
|
-
variants_params.each do |variant_data|
|
|
806
|
-
variant_data = variant_data.to_h.with_indifferent_access
|
|
807
|
-
variant_id = variant_data.delete(:id)
|
|
808
|
-
options = variant_data[:options]
|
|
809
|
-
|
|
810
|
-
if variant_id.present?
|
|
811
|
-
variant = variants_including_master.find_by_param!(variant_id)
|
|
812
|
-
variant.update!(variant_data)
|
|
813
|
-
variant_ids_in_payload << variant.id
|
|
814
|
-
mutated = true
|
|
815
|
-
elsif options.blank? || (options.is_a?(Array) && options.empty?)
|
|
816
|
-
# An entry with no options addresses the master variant. Building a
|
|
817
|
-
# non-master here would create a phantom duplicate (the auto-built
|
|
818
|
-
# master already exists, and `variants` excludes it). Upsert onto
|
|
819
|
-
# the master instead — the merchant-visible "default variant" on a
|
|
820
|
-
# simple product IS the master.
|
|
821
|
-
variant_data = variant_data.except(:options)
|
|
822
|
-
target = find_or_build_master
|
|
823
|
-
target.assign_attributes(variant_data)
|
|
824
|
-
target.save!
|
|
825
|
-
master_touched = true
|
|
826
|
-
mutated = true
|
|
827
|
-
else
|
|
828
|
-
variant = variants.build
|
|
829
|
-
variant.assign_attributes(variant_data)
|
|
830
|
-
variant.save!
|
|
831
|
-
variant_ids_in_payload << variant.id
|
|
832
|
-
mutated = true
|
|
833
|
-
end
|
|
834
|
-
end
|
|
835
|
-
|
|
836
|
-
# Remove variants not in the payload (only non-master). If only the
|
|
837
|
-
# master was touched (simple product), leave existing non-master
|
|
838
|
-
# variants alone — the payload is partial, not a full replacement.
|
|
839
|
-
if variant_ids_in_payload.any? && !master_touched
|
|
840
|
-
removed = variants.where.not(id: variant_ids_in_payload).destroy_all
|
|
841
|
-
mutated ||= removed.any?
|
|
842
|
-
end
|
|
843
|
-
|
|
844
|
-
sync_variant_state! if mutated
|
|
845
|
-
end
|
|
846
|
-
|
|
847
|
-
# Re-syncs the in-memory derived variant state after `apply_variants`
|
|
848
|
-
# mutates variants out-of-band (the variant counter is bumped via
|
|
849
|
-
# `Spree::Product.increment_counter` in a Variant callback, and
|
|
850
|
-
# `default_variant` is memoized). Without this, a freshly built/updated
|
|
851
|
-
# product serialized in the same request returns a stale `variant_count`
|
|
852
|
-
# and a stale `price` (delegated to the memoized `default_variant`).
|
|
853
|
-
#
|
|
854
|
-
# The `default_variant` memo reset here changes shape once master is
|
|
855
|
-
# removed (it becomes a `belongs_to` FK). See
|
|
856
|
-
# docs/plans/6.0-remove-master-variant.md (Phase 3).
|
|
857
|
-
# @return [void]
|
|
858
|
-
def sync_variant_state!
|
|
859
|
-
# `variant_count` is maintained by a direct counter update in a Variant
|
|
860
|
-
# callback, so the in-memory attribute is stale here — re-read it from the
|
|
861
|
-
# row without reloading the whole record.
|
|
862
|
-
self[:variant_count] = self.class.where(id: id).pick(:variant_count)
|
|
863
|
-
variants.reset
|
|
864
|
-
@default_variant = nil
|
|
865
|
-
@default_variant_id = nil
|
|
866
|
-
end
|
|
867
|
-
|
|
868
|
-
def add_associations_from_prototype
|
|
869
|
-
if prototype_id && prototype = Spree::Prototype.find_by(id: prototype_id)
|
|
870
|
-
self.option_types = prototype.option_types
|
|
871
|
-
self.taxons = prototype.taxons
|
|
872
|
-
end
|
|
893
|
+
# Scoped to the product's own store, matching `category_ids=`: a type
|
|
894
|
+
# pointing at another store's category must not drag it onto the product.
|
|
895
|
+
missing_category_ids = product_type.category_ids - product_categories.pluck(:category_id)
|
|
896
|
+
Spree::Category.for_store(assignable_store).where(id: missing_category_ids).
|
|
897
|
+
each { |category| categories << category }
|
|
873
898
|
end
|
|
874
899
|
|
|
875
900
|
def any_variants_not_track_inventory?
|
|
876
|
-
return true unless
|
|
901
|
+
return true unless store_preference(:track_inventory_levels)
|
|
877
902
|
|
|
878
|
-
if
|
|
879
|
-
|
|
903
|
+
if variants.loaded?
|
|
904
|
+
variants.any? { |v| !v.track_inventory? }
|
|
880
905
|
else
|
|
881
|
-
|
|
906
|
+
variants.where(track_inventory: false).exists?
|
|
882
907
|
end
|
|
883
908
|
end
|
|
884
909
|
|
|
885
|
-
#
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
values = option_values_hash.values
|
|
890
|
-
values = values.inject(values.shift) { |memo, value| memo.product(value).map(&:flatten) }
|
|
891
|
-
|
|
892
|
-
default_currency = store&.default_currency || Spree::Store.default.default_currency
|
|
893
|
-
master_price = master.price_in(default_currency).amount
|
|
894
|
-
|
|
895
|
-
values.each do |ids|
|
|
896
|
-
variant = variants.create!(option_value_ids: ids)
|
|
897
|
-
variant.set_price(default_currency, master_price) if master_price.present?
|
|
898
|
-
end
|
|
899
|
-
save
|
|
910
|
+
# Every product must have at least one variant. If none was built via the
|
|
911
|
+
# delegated setters or supplied as nested attributes, create an empty one.
|
|
912
|
+
def ensure_default_variant
|
|
913
|
+
variants.create! if variants.empty?
|
|
900
914
|
end
|
|
901
915
|
|
|
902
|
-
def
|
|
903
|
-
return
|
|
916
|
+
def set_default_variant
|
|
917
|
+
return if default_variant_id.present?
|
|
904
918
|
|
|
905
|
-
|
|
919
|
+
first_variant = preferred_default_variant
|
|
920
|
+
update_column(:default_variant_id, first_variant.id) if first_variant
|
|
906
921
|
end
|
|
907
922
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
923
|
+
# Re-point the default variant when the current one has been removed. Sticky
|
|
924
|
+
# otherwise — an in-stock change never re-points (see the plan's open question).
|
|
925
|
+
def auto_promote_default_variant
|
|
926
|
+
current = association(:default_variant).reader
|
|
927
|
+
return if current && current.deleted_at.nil?
|
|
911
928
|
|
|
912
|
-
|
|
913
|
-
|
|
929
|
+
next_variant = preferred_default_variant(reload: true)
|
|
930
|
+
update_column(:default_variant_id, next_variant&.id) if next_variant && next_variant.id != default_variant_id
|
|
914
931
|
end
|
|
915
932
|
|
|
916
|
-
|
|
917
|
-
|
|
933
|
+
# The product's public identity — its headline price, its SKU, and the
|
|
934
|
+
# Omnibus `prior_price`, which is a compliance claim about this shop's own
|
|
935
|
+
# pricing history. Where the operator sells the item themselves that is the
|
|
936
|
+
# listing that should speak for the product, not whichever seller happens
|
|
937
|
+
# to sort first.
|
|
938
|
+
def preferred_default_variant(reload: false)
|
|
939
|
+
candidates = reload ? variants.reload : variants
|
|
940
|
+
candidates.detect { |variant| variant.resolved_seller_id.nil? } || candidates.first
|
|
918
941
|
end
|
|
919
942
|
|
|
920
|
-
def
|
|
921
|
-
|
|
922
|
-
master.new_record? ||
|
|
923
|
-
master.changed? ||
|
|
924
|
-
(
|
|
925
|
-
Spree::Config.enable_legacy_default_price &&
|
|
926
|
-
master.default_price &&
|
|
927
|
-
(
|
|
928
|
-
master.default_price.new_record? ||
|
|
929
|
-
master.default_price.changed?
|
|
930
|
-
)
|
|
931
|
-
)
|
|
932
|
-
)
|
|
943
|
+
def assign_default_tax_category
|
|
944
|
+
self.tax_category = Spree::TaxCategory.default(assignable_store) if new_record? && self[:tax_category_id].blank?
|
|
933
945
|
end
|
|
934
946
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
# Fix for issue #5306
|
|
938
|
-
def save_master
|
|
939
|
-
if master_updated?
|
|
940
|
-
master.save!
|
|
941
|
-
@nested_changes = true
|
|
942
|
-
end
|
|
943
|
-
end
|
|
947
|
+
def stamp_template_delivery_profile
|
|
948
|
+
return if delivery_profile_id.present?
|
|
944
949
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
if Spree::Config.enable_legacy_default_price
|
|
949
|
-
# We call master.default_price here to ensure price is initialized.
|
|
950
|
-
# Required to avoid Variant#check_price validation failing on create.
|
|
951
|
-
master.default_price
|
|
952
|
-
end
|
|
950
|
+
self.delivery_profile_id = product_type&.delivery_profile_id ||
|
|
951
|
+
(store && Spree::DeliveryProfile.default_for(store)&.id)
|
|
952
|
+
end
|
|
953
953
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
954
|
+
def delivery_profile_must_belong_to_store
|
|
955
|
+
return if delivery_profile.nil? || store.nil?
|
|
956
|
+
return if delivery_profile.store_id == store_id
|
|
957
957
|
|
|
958
|
-
|
|
959
|
-
end
|
|
960
|
-
end
|
|
958
|
+
errors.add(:delivery_profile, :invalid)
|
|
961
959
|
end
|
|
962
960
|
|
|
963
|
-
|
|
964
|
-
|
|
961
|
+
# A seller from another store would put one store's catalog inside another
|
|
962
|
+
# store's seller — and every seller-scoped read is rooted in exactly that
|
|
963
|
+
# association.
|
|
964
|
+
def seller_must_belong_to_store
|
|
965
|
+
return if seller.nil? || store.nil?
|
|
966
|
+
return if seller.store_id == store_id
|
|
965
967
|
|
|
966
|
-
|
|
967
|
-
name = I18n.t('spree.seed.shipping.categories.default')
|
|
968
|
-
self.shipping_category = Spree::ShippingCategory.find_or_create_by!(name: name)
|
|
969
|
-
end
|
|
968
|
+
errors.add(:seller, :invalid)
|
|
970
969
|
end
|
|
971
970
|
|
|
972
971
|
def run_touch_callbacks
|
|
973
972
|
run_callbacks(:touch)
|
|
974
973
|
end
|
|
975
974
|
|
|
976
|
-
def
|
|
977
|
-
@
|
|
975
|
+
def category_and_ancestors
|
|
976
|
+
@category_and_ancestors ||= categories.map(&:self_and_ancestors).flatten.uniq
|
|
978
977
|
end
|
|
979
978
|
|
|
980
|
-
# Iterate through this
|
|
981
|
-
def
|
|
982
|
-
if
|
|
983
|
-
Spree::Products::
|
|
979
|
+
# Iterate through this product's categories and touch their timestamps in a batch
|
|
980
|
+
def touch_categories
|
|
981
|
+
if categories.any?
|
|
982
|
+
Spree::Products::TouchCategoriesJob.
|
|
984
983
|
set(wait: 5.seconds).
|
|
985
|
-
perform_later(
|
|
984
|
+
perform_later(category_and_ancestors.map(&:id))
|
|
986
985
|
end
|
|
987
986
|
end
|
|
988
987
|
|
|
@@ -993,48 +992,33 @@ module Spree
|
|
|
993
992
|
end
|
|
994
993
|
end
|
|
995
994
|
|
|
996
|
-
def
|
|
997
|
-
|
|
998
|
-
|
|
995
|
+
def remove_category(category)
|
|
996
|
+
removed_product_categories = product_categories.where(category: category)
|
|
997
|
+
removed_product_categories.each(&:remove_from_list)
|
|
999
998
|
end
|
|
1000
999
|
|
|
1001
1000
|
def discontinue_on_must_be_later_than_make_active_at
|
|
1002
|
-
Spree::Deprecation.warn('Spree::Product#discontinue_on_must_be_later_than_make_active_at is deprecated and will be removed in Spree 6.0.')
|
|
1003
1001
|
if discontinue_on < make_active_at
|
|
1004
1002
|
errors.add(:discontinue_on, :invalid_date_range)
|
|
1005
1003
|
end
|
|
1006
1004
|
end
|
|
1007
1005
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1006
|
+
# Mirrors the machine's bang events: an illegal move raised.
|
|
1007
|
+
def run_status_workflow(workflow)
|
|
1008
|
+
result = workflow.call(product: self)
|
|
1009
|
+
|
|
1010
|
+
if result.failure?
|
|
1011
|
+
# ResultError#to_s unwraps an ActiveModel::Errors into its full
|
|
1012
|
+
# messages; its `value` would inspect the object into the message.
|
|
1013
|
+
errors.add(:base, result.error.to_s)
|
|
1014
|
+
raise ActiveRecord::RecordInvalid, self
|
|
1015
|
+
end
|
|
1011
1016
|
|
|
1012
|
-
def requires_shipping_category?
|
|
1013
1017
|
true
|
|
1014
1018
|
end
|
|
1015
1019
|
|
|
1016
|
-
def
|
|
1020
|
+
def eligible_for_collection_matching?
|
|
1017
1021
|
previously_new_record? || tag_list_previously_changed? || available_on_previously_changed?
|
|
1018
1022
|
end
|
|
1019
|
-
|
|
1020
|
-
def after_activate
|
|
1021
|
-
# Implement your logic here
|
|
1022
|
-
end
|
|
1023
|
-
|
|
1024
|
-
def after_archive
|
|
1025
|
-
# Implement your logic here
|
|
1026
|
-
end
|
|
1027
|
-
|
|
1028
|
-
def after_draft
|
|
1029
|
-
# Implement your logic here
|
|
1030
|
-
end
|
|
1031
|
-
|
|
1032
|
-
def publish_product_activated_event
|
|
1033
|
-
publish_event('product.activated')
|
|
1034
|
-
end
|
|
1035
|
-
|
|
1036
|
-
def publish_product_archived_event
|
|
1037
|
-
publish_event('product.archived')
|
|
1038
|
-
end
|
|
1039
1023
|
end
|
|
1040
1024
|
end
|