spree_core 4.10.1 → 5.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/config/spree_core_manifest.js +4 -0
- data/app/assets/images/google_on_white_hdpi.png +0 -0
- data/app/controllers/spree/base_controller.rb +1 -4
- data/app/finders/spree/orders/find_complete.rb +14 -2
- data/app/finders/spree/products/find.rb +74 -23
- data/app/finders/spree/stores/find_current.rb +6 -2
- data/app/helpers/spree/addresses_helper.rb +106 -0
- data/app/helpers/spree/base_helper.rb +83 -55
- data/app/helpers/spree/currency_helper.rb +12 -0
- data/app/helpers/spree/images_helper.rb +18 -0
- data/app/helpers/spree/mail_helper.rb +24 -0
- data/app/helpers/spree/products_helper.rb +1 -20
- data/app/javascript/spree/core/controllers/address_autocomplete_controller.js +233 -0
- data/app/javascript/spree/core/controllers/address_form_controller.js +98 -0
- data/app/javascript/spree/core/controllers/enable_button_controller.js +29 -0
- data/app/javascript/spree/core/helpers/address_autocomplete/google_places_suggestions_provider.js +179 -0
- data/app/javascript/spree/core/helpers/debounce.js +9 -0
- data/app/javascript/spree/core/helpers/scroll_lock.js +25 -0
- data/app/jobs/spree/addresses/geocode_address_job.rb +31 -0
- data/app/jobs/spree/base_job.rb +1 -0
- data/app/jobs/spree/coupon_codes/bulk_generate_job.rb +17 -0
- data/app/jobs/spree/exports/generate_job.rb +12 -0
- data/app/jobs/spree/products/auto_match_taxons_job.rb +14 -0
- data/app/jobs/spree/products/touch_taxons_job.rb +12 -0
- data/app/jobs/spree/reports/generate_job.rb +12 -0
- data/app/jobs/spree/stock_locations/stock_items/create_job.rb +1 -1
- data/app/jobs/spree/themes/duplicate_components_job.rb +59 -0
- data/app/jobs/spree/themes/screenshot_job.rb +81 -0
- data/app/jobs/spree/variants/remove_from_incomplete_orders_job.rb +2 -0
- data/app/jobs/spree/variants/remove_line_item_job.rb +2 -0
- data/app/mailers/spree/base_mailer.rb +51 -0
- data/app/mailers/spree/export_mailer.rb +19 -0
- data/app/mailers/spree/report_mailer.rb +20 -0
- data/app/mailers/spree/test_mailer.rb +8 -0
- data/app/models/action_text/rich_text_decorator.rb +11 -0
- data/app/models/action_text/video_embed.rb +13 -0
- data/app/models/acts_as_taggable_on/tag_decorator.rb +10 -0
- data/app/models/concerns/spree/calculated_adjustments.rb +2 -0
- data/app/models/concerns/spree/display_on.rb +13 -0
- data/app/models/concerns/spree/has_one_link.rb +42 -0
- data/app/models/concerns/spree/has_page_links.rb +53 -0
- data/app/models/concerns/spree/metadata.rb +3 -7
- data/app/models/concerns/spree/multi_searchable.rb +21 -0
- data/app/models/concerns/spree/multi_store_resource.rb +9 -0
- data/app/models/concerns/spree/number_as_param.rb +4 -2
- data/app/models/concerns/spree/parameterizable_name.rb +21 -0
- data/app/models/concerns/spree/previewable.rb +17 -0
- data/app/models/concerns/spree/product_scopes.rb +7 -7
- data/app/models/concerns/spree/stores/setup.rb +52 -0
- data/app/models/concerns/spree/stores/socials.rb +68 -0
- data/app/models/concerns/spree/user_address.rb +4 -0
- data/app/models/concerns/spree/user_methods.rb +61 -11
- data/app/models/concerns/spree/user_reporting.rb +14 -6
- data/app/models/concerns/spree/user_roles.rb +1 -1
- data/app/models/spree/ability.rb +4 -2
- data/app/models/spree/address.rb +122 -28
- data/app/models/spree/adjustment.rb +4 -1
- data/app/models/spree/asset/support/active_storage.rb +1 -1
- data/app/models/spree/asset.rb +18 -6
- data/app/models/spree/base.rb +38 -7
- data/app/models/spree/base_analytics_event_handler.rb +49 -0
- data/app/models/spree/calculator.rb +1 -1
- data/app/models/spree/classification.rb +10 -1
- data/app/models/spree/country.rb +1 -1
- data/app/models/spree/coupon_code.rb +38 -0
- data/app/models/spree/credit_card.rb +4 -3
- data/app/models/spree/current.rb +9 -0
- data/app/models/spree/custom_domain.rb +53 -0
- data/app/models/spree/customer_return.rb +13 -1
- data/app/models/spree/data_feed.rb +1 -1
- data/app/models/spree/digital.rb +5 -6
- data/app/models/spree/digital_link.rb +11 -6
- data/app/models/spree/export.rb +172 -0
- data/app/models/spree/exports/orders.rb +23 -0
- data/app/models/spree/exports/products.rb +35 -0
- data/app/models/spree/gateway/bogus.rb +5 -0
- data/app/models/spree/gateway.rb +14 -4
- data/app/models/spree/gateway_customer.rb +13 -0
- data/app/models/spree/image/configuration/active_storage.rb +1 -1
- data/app/models/spree/inventory_unit.rb +1 -1
- data/app/models/spree/legacy_user.rb +3 -1
- data/app/models/spree/line_item.rb +37 -2
- data/app/models/spree/log_entry.rb +1 -1
- data/app/models/spree/option_type.rb +40 -6
- data/app/models/spree/option_type_prototype.rb +1 -1
- data/app/models/spree/option_value.rb +35 -5
- data/app/models/spree/option_value_variant.rb +2 -2
- data/app/models/spree/order/address_book.rb +34 -15
- data/app/models/spree/order/checkout.rb +12 -2
- data/app/models/spree/order/currency_updater.rb +1 -1
- data/app/models/spree/order/digital.rb +14 -3
- data/app/models/spree/order/emails.rb +1 -1
- data/app/models/spree/order/payments.rb +1 -13
- data/app/models/spree/order/store_credit.rb +17 -5
- data/app/models/spree/order/webhooks.rb +1 -1
- data/app/models/spree/order.rb +179 -49
- data/app/models/spree/order_promotion.rb +1 -1
- data/app/models/spree/order_updater.rb +9 -3
- data/app/models/spree/page.rb +184 -0
- data/app/models/spree/page_block.rb +69 -0
- data/app/models/spree/page_blocks/buttons.rb +29 -0
- data/app/models/spree/page_blocks/heading.rb +18 -0
- data/app/models/spree/page_blocks/image.rb +17 -0
- data/app/models/spree/page_blocks/link.rb +21 -0
- data/app/models/spree/page_blocks/mega_nav.rb +33 -0
- data/app/models/spree/page_blocks/mega_nav_with_subcategories.rb +32 -0
- data/app/models/spree/page_blocks/nav.rb +15 -0
- data/app/models/spree/page_blocks/newsletter_form.rb +18 -0
- data/app/models/spree/page_blocks/products/buy_buttons.rb +12 -0
- data/app/models/spree/page_blocks/products/price.rb +18 -0
- data/app/models/spree/page_blocks/products/quantity_selector.rb +12 -0
- data/app/models/spree/page_blocks/products/share.rb +8 -0
- data/app/models/spree/page_blocks/products/title.rb +15 -0
- data/app/models/spree/page_blocks/products/variant_picker.rb +9 -0
- data/app/models/spree/page_blocks/subheading.rb +17 -0
- data/app/models/spree/page_blocks/text.rb +16 -0
- data/app/models/spree/page_link.rb +59 -0
- data/app/models/spree/page_section.rb +215 -0
- data/app/models/spree/page_sections/announcement_bar.rb +30 -0
- data/app/models/spree/page_sections/collection_banner.rb +18 -0
- data/app/models/spree/page_sections/custom_code.rb +11 -0
- data/app/models/spree/page_sections/featured_posts.rb +43 -0
- data/app/models/spree/page_sections/featured_product.rb +46 -0
- data/app/models/spree/page_sections/featured_taxon.rb +88 -0
- data/app/models/spree/page_sections/featured_taxons.rb +45 -0
- data/app/models/spree/page_sections/footer.rb +94 -0
- data/app/models/spree/page_sections/header.rb +62 -0
- data/app/models/spree/page_sections/image_banner.rb +38 -0
- data/app/models/spree/page_sections/image_with_text.rb +48 -0
- data/app/models/spree/page_sections/main_password_footer.rb +18 -0
- data/app/models/spree/page_sections/main_password_header.rb +20 -0
- data/app/models/spree/page_sections/newsletter.rb +47 -0
- data/app/models/spree/page_sections/page_title.rb +19 -0
- data/app/models/spree/page_sections/post_details.rb +19 -0
- data/app/models/spree/page_sections/post_grid.rb +19 -0
- data/app/models/spree/page_sections/product_details.rb +16 -0
- data/app/models/spree/page_sections/product_grid.rb +13 -0
- data/app/models/spree/page_sections/related_products.rb +60 -0
- data/app/models/spree/page_sections/rich_text.rb +20 -0
- data/app/models/spree/page_sections/taxon_banner.rb +18 -0
- data/app/models/spree/page_sections/taxon_grid.rb +17 -0
- data/app/models/spree/page_sections/video.rb +99 -0
- data/app/models/spree/pages/account.rb +15 -0
- data/app/models/spree/pages/cart.rb +9 -0
- data/app/models/spree/pages/checkout.rb +9 -0
- data/app/models/spree/pages/custom.rb +34 -0
- data/app/models/spree/pages/homepage.rb +68 -0
- data/app/models/spree/pages/login.rb +15 -0
- data/app/models/spree/pages/password.rb +57 -0
- data/app/models/spree/pages/post.rb +27 -0
- data/app/models/spree/pages/post_list.rb +32 -0
- data/app/models/spree/pages/product_details.rb +29 -0
- data/app/models/spree/pages/search_results.rb +43 -0
- data/app/models/spree/pages/shop_all.rb +36 -0
- data/app/models/spree/pages/taxon.rb +29 -0
- data/app/models/spree/pages/taxon_list.rb +41 -0
- data/app/models/spree/pages/wishlist.rb +11 -0
- data/app/models/spree/payment/gateway_options.rb +13 -15
- data/app/models/spree/payment/processing.rb +1 -1
- data/app/models/spree/payment/webhooks.rb +1 -1
- data/app/models/spree/payment.rb +61 -12
- data/app/models/spree/payment_capture_event.rb +1 -1
- data/app/models/spree/payment_method/store_credit.rb +9 -1
- data/app/models/spree/payment_method.rb +26 -8
- data/app/models/spree/payment_source.rb +2 -2
- data/app/models/spree/post.rb +108 -0
- data/app/models/spree/post_category.rb +33 -0
- data/app/models/spree/preference.rb +1 -1
- data/app/models/spree/price.rb +10 -3
- data/app/models/spree/product/webhooks.rb +1 -1
- data/app/models/spree/product.rb +325 -54
- data/app/models/spree/product_option_type.rb +1 -1
- data/app/models/spree/product_promotion_rule.rb +1 -1
- data/app/models/spree/product_property.rb +4 -1
- data/app/models/spree/promotion/actions/create_line_items.rb +37 -2
- data/app/models/spree/promotion/rules/country.rb +22 -4
- data/app/models/spree/promotion/rules/currency.rb +21 -0
- data/app/models/spree/promotion/rules/item_total.rb +12 -3
- data/app/models/spree/promotion/rules/option_value.rb +5 -20
- data/app/models/spree/promotion/rules/product.rb +33 -1
- data/app/models/spree/promotion/rules/taxon.rb +31 -0
- data/app/models/spree/promotion/rules/user.rb +33 -4
- data/app/models/spree/promotion.rb +136 -15
- data/app/models/spree/promotion_action.rb +31 -1
- data/app/models/spree/promotion_action_line_item.rb +1 -1
- data/app/models/spree/promotion_category.rb +1 -1
- data/app/models/spree/promotion_handler/cart.rb +1 -1
- data/app/models/spree/promotion_handler/coupon.rb +46 -8
- data/app/models/spree/promotion_handler/free_shipping.rb +1 -1
- data/app/models/spree/promotion_handler/promotion_duplicator.rb +6 -5
- data/app/models/spree/promotion_rule.rb +23 -1
- data/app/models/spree/promotion_rule_taxon.rb +1 -1
- data/app/models/spree/promotion_rule_user.rb +1 -1
- data/app/models/spree/property.rb +11 -3
- data/app/models/spree/property_prototype.rb +1 -1
- data/app/models/spree/prototype.rb +1 -1
- data/app/models/spree/prototype_taxon.rb +1 -1
- data/app/models/spree/refund.rb +24 -4
- data/app/models/spree/refund_reason.rb +12 -2
- data/app/models/spree/reimbursement/credit.rb +1 -1
- data/app/models/spree/reimbursement/emails.rb +1 -1
- data/app/models/spree/reimbursement.rb +5 -3
- data/app/models/spree/reimbursement_type.rb +1 -1
- data/app/models/spree/report.rb +110 -0
- data/app/models/spree/report_line_item.rb +27 -0
- data/app/models/spree/report_line_items/products_performance.rb +76 -0
- data/app/models/spree/report_line_items/sales_total.rb +49 -0
- data/app/models/spree/reports/products_performance.rb +44 -0
- data/app/models/spree/reports/sales_total.rb +14 -0
- data/app/models/spree/return_authorization.rb +4 -1
- data/app/models/spree/return_authorization_reason.rb +1 -1
- data/app/models/spree/return_item.rb +2 -1
- data/app/models/spree/role.rb +5 -2
- data/app/models/spree/role_user.rb +2 -2
- data/app/models/spree/shipment/emails.rb +1 -1
- data/app/models/spree/shipment/webhooks.rb +1 -1
- data/app/models/spree/shipment.rb +14 -4
- data/app/models/spree/shipping_category.rb +1 -1
- data/app/models/spree/shipping_method.rb +48 -8
- data/app/models/spree/shipping_method_category.rb +1 -1
- data/app/models/spree/shipping_method_zone.rb +1 -1
- data/app/models/spree/shipping_rate.rb +21 -3
- data/app/models/spree/state.rb +1 -1
- data/app/models/spree/state_change.rb +1 -1
- data/app/models/spree/stock_item/webhooks.rb +1 -1
- data/app/models/spree/stock_item.rb +9 -6
- data/app/models/spree/stock_location.rb +35 -8
- data/app/models/spree/stock_movement/webhooks.rb +1 -1
- data/app/models/spree/stock_movement.rb +9 -3
- data/app/models/spree/stock_transfer.rb +41 -3
- data/app/models/spree/store.rb +345 -72
- data/app/models/spree/store_credit.rb +12 -4
- data/app/models/spree/store_credit_category.rb +1 -1
- data/app/models/spree/store_credit_event.rb +21 -1
- data/app/models/spree/store_credit_type.rb +1 -1
- data/app/models/spree/store_payment_method.rb +1 -1
- data/app/models/spree/store_product.rb +1 -1
- data/app/models/spree/store_promotion.rb +1 -1
- data/app/models/spree/tax_category.rb +15 -1
- data/app/models/spree/tax_rate.rb +1 -1
- data/app/models/spree/taxon.rb +210 -27
- data/app/models/spree/taxon_image/configuration/active_storage.rb +1 -1
- data/app/models/spree/taxon_rule.rb +25 -0
- data/app/models/spree/taxon_rules/available_on.rb +20 -0
- data/app/models/spree/taxon_rules/sale.rb +16 -0
- data/app/models/spree/taxon_rules/tag.rb +19 -0
- data/app/models/spree/taxonomy.rb +3 -2
- data/app/models/spree/theme.rb +200 -0
- data/app/models/spree/themes/default.rb +94 -0
- data/app/models/spree/variant/webhooks.rb +1 -1
- data/app/models/spree/variant.rb +211 -62
- data/app/models/spree/wished_item.rb +1 -1
- data/app/models/spree/wishlist.rb +1 -1
- data/app/models/spree/zone.rb +1 -1
- data/app/models/spree/zone_member.rb +1 -1
- data/app/presenters/spree/csv/order_line_item_presenter.rb +145 -0
- data/app/presenters/spree/csv/product_presenter.rb +63 -0
- data/app/presenters/spree/csv/product_variant_presenter.rb +130 -0
- data/app/services/spree/addresses/create.rb +31 -6
- data/app/services/spree/addresses/helper.rb +7 -4
- data/app/services/spree/addresses/update.rb +79 -12
- data/app/services/spree/cart/remove_out_of_stock_items.rb +56 -0
- data/app/services/spree/checkout/add_store_credit.rb +6 -1
- data/app/services/spree/checkout/advance.rb +44 -4
- data/app/services/spree/checkout/select_shipping_method.rb +2 -0
- data/app/services/spree/coupon_codes/bulk_generate.rb +37 -0
- data/app/services/spree/coupon_codes/coupon_codes_handler.rb +34 -0
- data/app/services/spree/orders/create_user_account.rb +70 -0
- data/app/services/spree/orders/update_contact_information.rb +19 -0
- data/app/services/spree/products/auto_match_taxons.rb +64 -0
- data/app/services/spree/products/duplicator.rb +121 -0
- data/app/services/spree/products/prepare_nested_attributes.rb +169 -0
- data/app/services/spree/seeds/admin_user.rb +22 -0
- data/app/services/spree/seeds/all.rb +1 -0
- data/app/services/spree/seeds/stores.rb +5 -10
- data/app/services/spree/seeds/zones.rb +2 -0
- data/app/services/spree/tags/bulk_add.rb +38 -0
- data/app/services/spree/tags/bulk_remove.rb +24 -0
- data/app/services/spree/taxons/add_products.rb +39 -0
- data/app/services/spree/taxons/regenerate_products.rb +53 -0
- data/app/services/spree/taxons/remove_products.rb +53 -0
- data/app/services/spree/taxons/touch_featured_sections.rb +21 -0
- data/app/services/spree/themes/duplicator.rb +40 -0
- data/app/services/spree/variants/remove_line_items.rb +1 -1
- data/app/sorters/spree/classifications/sort.rb +68 -0
- data/app/sorters/spree/products/sort.rb +2 -3
- data/app/views/action_text/video_embeds/_thumbnail.html.erb +1 -0
- data/app/views/action_text/video_embeds/_video_embed.html.erb +3 -0
- data/app/views/active_storage/blobs/_blob.html.erb +20 -0
- data/app/views/layouts/action_text/contents/_content.html.erb +3 -0
- data/app/views/layouts/spree/base_mailer.html.erb +46 -0
- data/app/views/spree/addresses/_form.html.erb +58 -0
- data/app/views/spree/addresses/_suggestions_box.erb +14 -0
- data/app/views/spree/export_mailer/export_done.html.erb +15 -0
- data/app/views/spree/report_mailer/report_done.html.erb +15 -0
- data/app/views/spree/shared/_base_mailer_footer.html.erb +12 -0
- data/app/views/spree/shared/_base_mailer_header.html.erb +6 -0
- data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +456 -0
- data/app/views/spree/shared/_google_places_api_loader.html.erb +7 -0
- data/app/views/spree/shared/_mailer_line_item.html.erb +12 -0
- data/app/views/spree/shared/_mailer_logo.html.erb +41 -0
- data/app/views/spree/shared/_payment.html.erb +41 -0
- data/app/views/spree/test_mailer/test_email.html.erb +40 -0
- data/app/views/spree/test_mailer/test_email.text.erb +4 -0
- data/config/i18n-tasks.yml +178 -0
- data/config/importmap.rb +14 -0
- data/config/initializers/acts_as_taggable_on.rb +2 -0
- data/config/initializers/inflections.rb +2 -0
- data/config/initializers/mobility.rb +4 -0
- data/config/initializers/oembed.rb +1 -0
- data/config/locales/en.yml +823 -413
- data/config/routes.rb +6 -5
- data/db/migrate/20210914000000_spree_four_three.rb +0 -79
- data/db/migrate/20240913143518_change_default_value_of_spree_option_types_filterable.rb +5 -0
- data/db/migrate/20240914153106_add_display_on_to_spree_properties.rb +5 -0
- data/db/migrate/20240915144935_add_position_to_spree_properties.rb +6 -0
- data/db/migrate/20241004181911_create_spree_coupon_codes.rb +15 -0
- data/db/migrate/20241005093437_add_multi_code_to_spree_promotions.rb +14 -0
- data/db/migrate/20241014140140_translate_rich_texts.rb +17 -0
- data/db/migrate/20241030134309_create_spree_exports.rb +23 -0
- data/db/migrate/20241104083457_migrate_spree_promotion_rules_option_value_eligible_values.rb +16 -0
- data/db/migrate/20241123110646_add_estimated_transit_fields_to_spree_shipping_methods.rb +6 -0
- data/db/migrate/20241127193411_create_spree_taxon_rules.rb +13 -0
- data/db/migrate/20241127223627_add_rules_match_policy_and_sort_order_to_spree_taxons.rb +6 -0
- data/db/migrate/20241128103947_add_automatic_to_spree_taxons.rb +5 -0
- data/db/migrate/20241218183905_add_gateway_customer_profile_id_to_spree_payment_sources.rb +5 -0
- data/db/migrate/20250107220432_add_accept_marketing_and_signup_for_an_account_to_spree_orders.rb +6 -0
- data/db/migrate/20250110171203_add_quick_checkout_to_spree_addresses.rb +6 -0
- data/db/migrate/20250113180019_add_preferences_to_spree_stores.rb +5 -0
- data/db/migrate/20250114193857_add_metadata_to_spree_stores.rb +13 -0
- data/db/migrate/20250119165904_create_spree_custom_domains.rb +22 -0
- data/db/migrate/20250120094216_create_page_builder_models.rb +78 -0
- data/db/migrate/20250120152208_add_default_locale_to_action_text_rich_texts.rb +7 -0
- data/db/migrate/20250121160028_create_spree_posts_and_spree_post_categories.rb +33 -0
- data/db/migrate/20250122113708_add_first_and_last_name_to_spree_admin_class.rb +9 -0
- data/db/migrate/20250123135358_add_custom_code_fields_to_spree_store.rb +7 -0
- data/db/migrate/20250127083740_add_kind_to_spree_properties.rb +5 -0
- data/db/migrate/20250127112758_add_latitude_and_longitude_to_spree_addresses.rb +6 -0
- data/db/migrate/20250127151258_add_phone_to_spree_users.rb +5 -0
- data/db/migrate/20250204162453_create_spree_reports.rb +13 -0
- data/db/migrate/20250207084000_add_accepts_email_marketing_field_to_spree_users_table.rb +6 -0
- data/db/migrate/20250217171018_create_action_text_video_embeds.rb +11 -0
- data/db/migrate/20250304115943_add_performed_by_to_spree_reimbursements.rb +5 -0
- data/db/migrate/20250305121352_remove_page_builder_indices.rb +11 -0
- data/db/migrate/20250305121657_remove_spree_posts_indices.rb +7 -0
- data/db/migrate/20250311105934_create_spree_gateway_customers.rb +18 -0
- data/db/migrate/20250312202705_add_unique_index_on_promotion_rules_associations.rb +75 -0
- data/db/migrate/20250313104226_add_user_type_to_spree_role_users.rb +18 -0
- data/db/migrate/20250313175830_add_unique_index_on_promotion_action_line_items.rb +29 -0
- data/db/migrate/20250314144210_create_spree_taggings_and_spree_tags.rb +38 -0
- data/lib/generators/spree/authentication/custom/custom_generator.rb +49 -0
- data/lib/generators/spree/authentication/custom/templates/authentication_helpers.rb.tt +50 -0
- data/lib/generators/spree/authentication/devise/devise_generator.rb +57 -0
- data/lib/generators/spree/authentication/devise/templates/authentication_helpers.rb.tt +50 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +1 -1
- data/lib/generators/spree/dummy/templates/rails/database.yml +1 -0
- data/lib/generators/spree/dummy/templates/rails/test.rb +1 -1
- data/lib/generators/spree/install/install_generator.rb +21 -36
- data/lib/generators/spree/install/templates/config/initializers/spree.rb +40 -6
- data/lib/normalize_string.rb +18 -0
- data/lib/spree/analytics.rb +11 -0
- data/lib/spree/core/components.rb +1 -1
- data/lib/spree/core/configuration.rb +14 -11
- data/lib/spree/core/controller_helpers/auth.rb +0 -26
- data/lib/spree/core/controller_helpers/order.rb +77 -12
- data/lib/spree/core/controller_helpers/search.rb +2 -0
- data/lib/spree/core/controller_helpers/store.rb +0 -5
- data/lib/spree/core/controller_helpers/strong_parameters.rb +4 -0
- data/lib/spree/core/controller_helpers/turbo.rb +19 -0
- data/lib/spree/core/dependencies.rb +3 -5
- data/lib/spree/core/engine.rb +158 -7
- data/lib/spree/core/preferences/configuration.rb +2 -44
- data/lib/spree/core/preferences/preferable.rb +9 -0
- data/lib/spree/core/preferences/preferable_class_methods.rb +11 -1
- data/lib/spree/core/preferences/runtime_configuration.rb +13 -2
- data/lib/spree/core/search/base.rb +2 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +61 -11
- data/lib/spree/i18n.rb +5 -8
- data/lib/spree/migrations.rb +1 -1
- data/lib/spree/permitted_attributes.rb +24 -15
- data/lib/spree/testing_support/authorization_helpers.rb +9 -6
- data/lib/spree/testing_support/capybara_config.rb +11 -0
- data/lib/spree/testing_support/common_rake.rb +20 -12
- data/lib/spree/testing_support/factories/calculator_factory.rb +16 -0
- data/lib/spree/testing_support/factories/country_factory.rb +8 -0
- data/lib/spree/testing_support/factories/coupon_code_factory.rb +7 -0
- data/lib/spree/testing_support/factories/custom_domain_factory.rb +7 -0
- data/lib/spree/testing_support/factories/export_factory.rb +32 -0
- data/lib/spree/testing_support/factories/gateway_customer_factory.rb +7 -0
- data/lib/spree/testing_support/factories/order_factory.rb +14 -3
- data/lib/spree/testing_support/factories/page_block_factory.rb +21 -0
- data/lib/spree/testing_support/factories/page_factory.rb +33 -0
- data/lib/spree/testing_support/factories/page_link_factory.rb +7 -0
- data/lib/spree/testing_support/factories/page_section_factory.rb +24 -0
- data/lib/spree/testing_support/factories/payment_factory.rb +2 -2
- data/lib/spree/testing_support/factories/post_category_factory.rb +7 -0
- data/lib/spree/testing_support/factories/post_factory.rb +10 -0
- data/lib/spree/testing_support/factories/product_factory.rb +3 -8
- data/lib/spree/testing_support/factories/product_property_factory.rb +1 -1
- data/lib/spree/testing_support/factories/promotion_action_factory.rb +5 -0
- data/lib/spree/testing_support/factories/promotion_factory.rb +7 -9
- data/lib/spree/testing_support/factories/promotion_rule_factory.rb +12 -0
- data/lib/spree/testing_support/factories/property_factory.rb +1 -1
- data/lib/spree/testing_support/factories/report_factory.rb +33 -0
- data/lib/spree/testing_support/factories/role_user_factory.rb +7 -0
- data/lib/spree/testing_support/factories/shipping_method_factory.rb +9 -0
- data/lib/spree/testing_support/factories/stock_transfer_factory.rb +5 -2
- data/lib/spree/testing_support/factories/store_factory.rb +6 -9
- data/lib/spree/testing_support/factories/taxon_factory.rb +13 -0
- data/lib/spree/testing_support/factories/taxon_rule_factory.rb +38 -0
- data/lib/spree/testing_support/factories/theme_factory.rb +14 -0
- data/lib/spree/testing_support/factories/user_factory.rb +13 -11
- data/lib/spree/testing_support/factories/variant_factory.rb +23 -5
- data/lib/spree/testing_support/jobs.rb +1 -7
- data/lib/spree/testing_support/metadata.rb +13 -1
- data/lib/spree/testing_support/order_walkthrough.rb +1 -7
- data/lib/spree/testing_support/preferences.rb +1 -4
- data/lib/spree/testing_support/store.rb +26 -0
- data/lib/spree_core.rb +1 -0
- data/vendor/javascript/@rails--request.js.js +4 -0
- data/vendor/javascript/@stimulus-components--auto-submit.js +4 -0
- data/vendor/javascript/stimulus-reveal-controller.js +4 -0
- data/vendor/javascript/tailwindcss-stimulus-components.js +4 -0
- metadata +340 -197
- data/Gemfile +0 -3
- data/app/finders/spree/cms_pages/find.rb +0 -41
- data/app/finders/spree/menus/find.rb +0 -11
- data/app/models/concerns/spree/display_link.rb +0 -30
- data/app/models/spree/cms/pages/feature_page.rb +0 -7
- data/app/models/spree/cms/pages/homepage.rb +0 -20
- data/app/models/spree/cms/pages/standard_page.rb +0 -4
- data/app/models/spree/cms/sections/featured_article.rb +0 -22
- data/app/models/spree/cms/sections/hero_image.rb +0 -38
- data/app/models/spree/cms/sections/image_gallery.rb +0 -97
- data/app/models/spree/cms/sections/product_carousel.rb +0 -14
- data/app/models/spree/cms/sections/rich_text_content.rb +0 -13
- data/app/models/spree/cms/sections/side_by_side_images.rb +0 -68
- data/app/models/spree/cms_page.rb +0 -70
- data/app/models/spree/cms_section.rb +0 -69
- data/app/models/spree/cms_section_image.rb +0 -9
- data/app/models/spree/cms_section_image_one.rb +0 -4
- data/app/models/spree/cms_section_image_three.rb +0 -4
- data/app/models/spree/cms_section_image_two.rb +0 -4
- data/app/models/spree/icon.rb +0 -7
- data/app/models/spree/linkable/homepage.rb +0 -3
- data/app/models/spree/linkable/uri.rb +0 -3
- data/app/models/spree/menu.rb +0 -66
- data/app/models/spree/menu_item.rb +0 -72
- data/brakeman.ignore +0 -328
- data/db/migrate/20211201202851_update_linkable_resource_types.rb +0 -10
- data/db/migrate/20220329113557_fix_cms_pages_unique_indexes.rb +0 -8
- data/lib/generators/spree/custom_authentication/custom_authentication_generator.rb +0 -23
- data/lib/generators/spree/custom_authentication/templates/authentication_helpers.rb.tt +0 -23
- data/lib/generators/spree/custom_user/custom_user_generator.rb +0 -46
- data/lib/generators/spree/custom_user/templates/current_user_helpers.rb.tt +0 -15
- data/lib/generators/spree/custom_user/templates/initializer.rb.tt +0 -1
- data/lib/generators/spree/custom_user/templates/migration.rb.tt +0 -7
- data/lib/generators/spree/dummy/templates/package.json +0 -12
- data/lib/spree/core/product_duplicator.rb +0 -85
- data/lib/spree/core/runtime_configuration.rb +0 -10
- data/lib/spree/testing_support/factories/cms_page_factory.rb +0 -20
- data/lib/spree/testing_support/factories/cms_section_factory.rb +0 -31
- data/lib/spree/testing_support/factories/icon_factory.rb +0 -9
- data/lib/spree/testing_support/factories/menu_factory.rb +0 -16
- data/lib/spree/testing_support/factories/menu_item_factory.rb +0 -10
- data/script/rails +0 -9
- data/spec/fixtures/favicon.ico +0 -0
- data/spec/fixtures/files/icon_256x256.gif +0 -0
- data/spec/fixtures/files/icon_256x256.png +0 -0
- data/spec/fixtures/files/icon_512x512.png +0 -0
- data/spec/fixtures/files/img_256x128.png +0 -0
- data/spec/fixtures/text-file.txt +0 -1
- data/spec/fixtures/thinking-cat.jpg +0 -0
- data/spree_core.gemspec +0 -62
data/app/models/spree/variant.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Spree
|
2
|
-
class Variant < Spree
|
2
|
+
class Variant < Spree.base_class
|
3
3
|
acts_as_paranoid
|
4
4
|
acts_as_list scope: :product
|
5
5
|
|
@@ -7,7 +7,10 @@ module Spree
|
|
7
7
|
include Spree::Metadata
|
8
8
|
include Spree::Variant::Webhooks
|
9
9
|
|
10
|
-
MEMOIZED_METHODS = %w(purchasable in_stock backorderable tax_category options_text compare_at_price)
|
10
|
+
MEMOIZED_METHODS = %w(purchasable in_stock on_sale backorderable tax_category options_text compare_at_price)
|
11
|
+
|
12
|
+
DIMENSION_UNITS = %w[mm cm in ft]
|
13
|
+
WEIGHT_UNITS = %w[g kg lb oz]
|
11
14
|
|
12
15
|
belongs_to :product, -> { with_deleted }, touch: true, class_name: 'Spree::Product', inverse_of: :variants
|
13
16
|
belongs_to :tax_category, class_name: 'Spree::TaxCategory', optional: true
|
@@ -55,7 +58,7 @@ module Spree
|
|
55
58
|
|
56
59
|
validate :check_price
|
57
60
|
|
58
|
-
validates :
|
61
|
+
validates :option_value_variants, presence: true, unless: :is_master?
|
59
62
|
|
60
63
|
with_options numericality: { greater_than_or_equal_to: 0, allow_nil: true } do
|
61
64
|
validates :cost_price
|
@@ -64,25 +67,30 @@ module Spree
|
|
64
67
|
validates :sku, uniqueness: { conditions: -> { where(deleted_at: nil) }, case_sensitive: false, scope: spree_base_uniqueness_scope },
|
65
68
|
allow_blank: true, unless: :disable_sku_validation?
|
66
69
|
|
70
|
+
validates :dimensions_unit, inclusion: { in: DIMENSION_UNITS }, allow_blank: true
|
71
|
+
validates :weight_unit, inclusion: { in: WEIGHT_UNITS }, allow_blank: true
|
72
|
+
|
67
73
|
after_create :create_stock_items
|
68
74
|
after_create :set_master_out_of_stock, unless: :is_master?
|
75
|
+
after_commit :clear_line_items_cache, on: :update
|
76
|
+
after_update_commit :handle_track_inventory_change
|
77
|
+
|
78
|
+
after_commit :remove_prices_from_master_variant, on: [:create, :update], unless: :is_master?
|
79
|
+
after_commit :remove_stock_items_from_master_variant, on: :create, unless: :is_master?
|
69
80
|
|
70
81
|
after_touch :clear_in_stock_cache
|
71
82
|
|
72
|
-
scope :in_stock, -> {
|
73
|
-
scope :backorderable, -> {
|
83
|
+
scope :in_stock, -> { left_joins(:stock_items).where("#{Spree::StockItem.table_name}.count_on_hand > ? OR #{Spree::Variant.table_name}.track_inventory = ?", 0, false) }
|
84
|
+
scope :backorderable, -> { left_joins(:stock_items).where(spree_stock_items: { backorderable: true }) }
|
74
85
|
scope :in_stock_or_backorderable, -> { in_stock.or(backorderable) }
|
75
86
|
|
76
87
|
scope :eligible, -> {
|
77
88
|
where(is_master: false).or(
|
78
89
|
where(
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
HAVING COUNT(*) = 1
|
84
|
-
)
|
85
|
-
SQL
|
90
|
+
product_id: Spree::Variant.
|
91
|
+
select(:product_id).
|
92
|
+
group(:product_id).
|
93
|
+
having("COUNT(#{Spree::Variant.table_name}.id) = 1")
|
86
94
|
)
|
87
95
|
)
|
88
96
|
}
|
@@ -99,7 +107,7 @@ module Spree
|
|
99
107
|
|
100
108
|
scope :for_currency_and_available_price_amount, ->(currency = nil) do
|
101
109
|
currency ||= Spree::Store.default.default_currency
|
102
|
-
joins(:prices).where(
|
110
|
+
joins(:prices).where("#{Spree::Price.table_name}.currency = ?", currency).where("#{Spree::Price.table_name}.amount IS NOT NULL").distinct
|
103
111
|
end
|
104
112
|
|
105
113
|
scope :active, ->(currency = nil) do
|
@@ -114,6 +122,36 @@ module Spree
|
|
114
122
|
joins(:option_values).where(Spree::OptionValue.table_name => { name: option_value, option_type_id: option_type_ids })
|
115
123
|
}
|
116
124
|
|
125
|
+
scope :with_digital_assets, -> { joins(:digitals) }
|
126
|
+
|
127
|
+
if defined?(PgSearch)
|
128
|
+
include PgSearch::Model
|
129
|
+
|
130
|
+
pg_search_scope :search_by_sku, against: :sku, using: { tsearch: { prefix: true } }
|
131
|
+
|
132
|
+
pg_search_scope :search_by_sku_or_options,
|
133
|
+
against: :sku,
|
134
|
+
using: { tsearch: { prefix: true } },
|
135
|
+
associated_against: { option_values: %i[presentation] }
|
136
|
+
|
137
|
+
pg_search_scope :search_by_name_sku_or_options, against: :sku, associated_against: {
|
138
|
+
product: %i[name],
|
139
|
+
option_values: %i[presentation]
|
140
|
+
}, using: { tsearch: { prefix: true } }
|
141
|
+
|
142
|
+
scope :multi_search, lambda { |query|
|
143
|
+
return none if query.blank? || query.length < 3
|
144
|
+
|
145
|
+
search_by_name_sku_or_options(query)
|
146
|
+
}
|
147
|
+
else
|
148
|
+
scope :multi_search, lambda { |query|
|
149
|
+
return none if query.blank? || query.length < 3
|
150
|
+
|
151
|
+
product_name_or_sku_cont(query)
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
117
155
|
# FIXME: cost price should be represented with DisplayMoney class
|
118
156
|
LOCALIZED_NUMBERS = %w(cost_price weight depth width height)
|
119
157
|
|
@@ -123,6 +161,24 @@ module Spree
|
|
123
161
|
end
|
124
162
|
end
|
125
163
|
|
164
|
+
accepts_nested_attributes_for(
|
165
|
+
:stock_items,
|
166
|
+
reject_if: ->(attributes) { attributes['stock_location_id'].blank? || attributes['count_on_hand'].blank? },
|
167
|
+
allow_destroy: false
|
168
|
+
)
|
169
|
+
|
170
|
+
accepts_nested_attributes_for(
|
171
|
+
:prices,
|
172
|
+
reject_if: ->(attributes) { attributes['currency'].blank? || attributes['amount'].blank? },
|
173
|
+
allow_destroy: true
|
174
|
+
)
|
175
|
+
|
176
|
+
accepts_nested_attributes_for(
|
177
|
+
:option_value_variants,
|
178
|
+
reject_if: ->(attributes) { attributes['option_value_id'].blank? },
|
179
|
+
allow_destroy: false
|
180
|
+
)
|
181
|
+
|
126
182
|
self.whitelisted_ransackable_associations = %w[option_values product tax_category prices default_price]
|
127
183
|
self.whitelisted_ransackable_attributes = %w[weight depth width height sku discontinue_on is_master cost_price cost_currency track_inventory deleted_at]
|
128
184
|
self.whitelisted_ransackable_scopes = %i(product_name_or_sku_cont search_by_product_name_or_sku)
|
@@ -133,7 +189,9 @@ module Spree
|
|
133
189
|
sku_condition = arel_table[:sku].lower.matches(query_pattern)
|
134
190
|
|
135
191
|
if Spree.use_translations?
|
136
|
-
|
192
|
+
translation_arel_table = Product::Translation.arel_table.alias(Product.translation_table_alias)[:name]
|
193
|
+
product_name_condition = translation_arel_table.lower.matches(query_pattern)
|
194
|
+
|
137
195
|
joins(:product).
|
138
196
|
join_translation_table(Product).
|
139
197
|
where(product_name_condition.or(sku_condition))
|
@@ -147,6 +205,14 @@ module Spree
|
|
147
205
|
product_name_or_sku_cont(query)
|
148
206
|
end
|
149
207
|
|
208
|
+
def human_name
|
209
|
+
@human_name ||= option_values.
|
210
|
+
joins(option_type: :product_option_types).
|
211
|
+
merge(product.product_option_types).
|
212
|
+
reorder('spree_product_option_types.position').
|
213
|
+
pluck(:presentation).join('/')
|
214
|
+
end
|
215
|
+
|
150
216
|
def available?
|
151
217
|
!discontinued? && product.available?
|
152
218
|
end
|
@@ -183,31 +249,61 @@ module Spree
|
|
183
249
|
!!deleted_at
|
184
250
|
end
|
185
251
|
|
252
|
+
# Returns default Image for Variant
|
253
|
+
# @return [Spree::Image]
|
254
|
+
def default_image
|
255
|
+
@default_image ||= if images.size.positive?
|
256
|
+
images.first
|
257
|
+
else
|
258
|
+
product.default_image
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Returns secondary Image for Variant
|
263
|
+
# @return [Spree::Image]
|
264
|
+
def secondary_image
|
265
|
+
@secondary_image ||= if images.size > 1
|
266
|
+
images.second
|
267
|
+
else
|
268
|
+
product.secondary_image
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
# Returns additional Images for Variant
|
273
|
+
# @return [Array<Spree::Image>]
|
274
|
+
def additional_images
|
275
|
+
@additional_images ||= (images + product.images).uniq.find_all { |image| image.id != default_image&.id }
|
276
|
+
end
|
277
|
+
|
186
278
|
# Returns an array of hashes with the option type name, value and presentation
|
187
279
|
# @return [Array<Hash>]
|
188
280
|
def options
|
189
|
-
option_values.
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
281
|
+
@options ||= option_values.
|
282
|
+
includes(option_type: :product_option_types).
|
283
|
+
merge(product.product_option_types).
|
284
|
+
reorder('spree_product_option_types.position').
|
285
|
+
map do |option_value|
|
286
|
+
{
|
287
|
+
name: option_value.option_type.name,
|
288
|
+
value: option_value.name,
|
289
|
+
presentation: option_value.presentation
|
290
|
+
}
|
291
|
+
end
|
196
292
|
end
|
197
293
|
|
198
294
|
def options=(options = {})
|
199
295
|
options.each do |option|
|
200
296
|
next if option[:name].blank? || option[:value].blank?
|
201
297
|
|
202
|
-
set_option_value(option[:name], option[:value])
|
298
|
+
set_option_value(option[:name], option[:value], option[:position])
|
203
299
|
end
|
204
300
|
end
|
205
301
|
|
206
|
-
def set_option_value(opt_name, opt_value)
|
302
|
+
def set_option_value(opt_name, opt_value, opt_type_position = nil)
|
207
303
|
# no option values on master
|
208
304
|
return if is_master
|
209
305
|
|
210
|
-
option_type = Spree::OptionType.where(
|
306
|
+
option_type = Spree::OptionType.where(name: opt_name.parameterize).first_or_initialize do |o|
|
211
307
|
o.name = o.presentation = opt_name
|
212
308
|
o.save!
|
213
309
|
end
|
@@ -216,16 +312,21 @@ module Spree
|
|
216
312
|
|
217
313
|
if current_value.nil?
|
218
314
|
# then we have to check to make sure that the product has the option type
|
219
|
-
|
220
|
-
|
221
|
-
|
315
|
+
product_option_type = if (existing_prod_ot = product.product_option_types.find { |ot| ot.option_type_id == option_type.id })
|
316
|
+
existing_prod_ot
|
317
|
+
else
|
318
|
+
product_option_type = product.product_option_types.new
|
319
|
+
product_option_type.option_type = option_type
|
320
|
+
end
|
321
|
+
product_option_type.position = opt_type_position if opt_type_position
|
322
|
+
product_option_type.save! if product_option_type.new_record? || product_option_type.changed?
|
222
323
|
else
|
223
|
-
return if current_value.name.
|
324
|
+
return if current_value.name.parameterize == opt_value.parameterize
|
224
325
|
|
225
326
|
option_values.delete(current_value)
|
226
327
|
end
|
227
328
|
|
228
|
-
option_value = option_type.option_values.where(
|
329
|
+
option_value = option_type.option_values.where(name: opt_value.parameterize).first_or_initialize do |o|
|
229
330
|
o.name = o.presentation = opt_value
|
230
331
|
o.save!
|
231
332
|
end
|
@@ -235,28 +336,39 @@ module Spree
|
|
235
336
|
end
|
236
337
|
|
237
338
|
def find_option_value(opt_name)
|
238
|
-
option_values.detect { |o| o.option_type.name.
|
339
|
+
option_values.includes(:option_type).detect { |o| o.option_type.name.parameterize == opt_name.parameterize }
|
239
340
|
end
|
240
341
|
|
241
|
-
def option_value(
|
242
|
-
|
342
|
+
def option_value(option_type)
|
343
|
+
if option_type.is_a?(Spree::OptionType)
|
344
|
+
option_values.detect { |o| o.option_type_id == option_type.id }.try(:presentation)
|
345
|
+
else
|
346
|
+
find_option_value(option_type).try(:presentation)
|
347
|
+
end
|
243
348
|
end
|
244
349
|
|
245
350
|
def price_in(currency)
|
246
351
|
currency = currency&.upcase
|
247
|
-
find_or_build_price = lambda do
|
248
|
-
if prices.loaded?
|
249
|
-
prices.detect { |price| price.currency == currency } || prices.build(currency: currency)
|
250
|
-
else
|
251
|
-
prices.find_or_initialize_by(currency: currency)
|
252
|
-
end
|
253
|
-
end
|
254
352
|
|
255
|
-
|
256
|
-
|
353
|
+
price = if prices.loaded? && prices.any?
|
354
|
+
prices.detect { |p| p.currency == currency }
|
355
|
+
else
|
356
|
+
prices.find_by(currency: currency)
|
357
|
+
end
|
358
|
+
|
359
|
+
if price.nil?
|
360
|
+
return Spree::Price.new(
|
361
|
+
currency: currency,
|
362
|
+
variant_id: id
|
363
|
+
)
|
257
364
|
end
|
365
|
+
|
366
|
+
price
|
258
367
|
rescue TypeError
|
259
|
-
|
368
|
+
Spree::Price.new(
|
369
|
+
currency: currency,
|
370
|
+
variant_id: id
|
371
|
+
)
|
260
372
|
end
|
261
373
|
|
262
374
|
def amount_in(currency)
|
@@ -306,13 +418,13 @@ module Spree
|
|
306
418
|
end
|
307
419
|
|
308
420
|
def in_stock?
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
421
|
+
@in_stock ||= if association(:stock_items).loaded? && association(:stock_locations).loaded?
|
422
|
+
total_on_hand.positive?
|
423
|
+
else
|
424
|
+
Rails.cache.fetch(in_stock_cache_key, version: cache_version) do
|
425
|
+
total_on_hand.positive?
|
426
|
+
end
|
427
|
+
end
|
316
428
|
end
|
317
429
|
|
318
430
|
def backorderable?
|
@@ -321,6 +433,10 @@ module Spree
|
|
321
433
|
end
|
322
434
|
end
|
323
435
|
|
436
|
+
def on_sale?(currency)
|
437
|
+
@on_sale ||= price_in(currency)&.discounted?
|
438
|
+
end
|
439
|
+
|
324
440
|
delegate :total_on_hand, :can_supply?, to: :quantifier
|
325
441
|
|
326
442
|
alias is_backorderable? backorderable?
|
@@ -343,6 +459,12 @@ module Spree
|
|
343
459
|
(width || 0) + (height || 0) + (depth || 0)
|
344
460
|
end
|
345
461
|
|
462
|
+
# Returns the weight unit for the variant
|
463
|
+
# @return [String]
|
464
|
+
def weight_unit
|
465
|
+
attributes['weight_unit'] || Spree::Store.default.preferred_weight_unit
|
466
|
+
end
|
467
|
+
|
346
468
|
def discontinue!
|
347
469
|
update_attribute(:discontinue_on, Time.current)
|
348
470
|
end
|
@@ -355,9 +477,17 @@ module Spree
|
|
355
477
|
@backordered ||= !in_stock? && stock_items.exists?(backorderable: true)
|
356
478
|
end
|
357
479
|
|
358
|
-
# Is this variant
|
480
|
+
# Is this variant purely digital? (no physical product)
|
359
481
|
def digital?
|
360
|
-
|
482
|
+
product.digital?
|
483
|
+
end
|
484
|
+
|
485
|
+
def with_digital_assets?
|
486
|
+
digitals.any?
|
487
|
+
end
|
488
|
+
|
489
|
+
def clear_in_stock_cache
|
490
|
+
Rails.cache.delete(in_stock_cache_key)
|
361
491
|
end
|
362
492
|
|
363
493
|
private
|
@@ -386,14 +516,18 @@ module Spree
|
|
386
516
|
|
387
517
|
# Ensures a new variant takes the product master price when price is not supplied
|
388
518
|
def check_price
|
389
|
-
if
|
390
|
-
return errors.add(:base, :no_master_variant_found_to_infer_price) unless product&.master
|
391
|
-
return errors.add(:base, :must_supply_price_for_variant_or_master) if self == product.master
|
519
|
+
return if (has_default_price? && default_price.valid?) || prices.any?
|
392
520
|
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
521
|
+
infer_price_from_default_variant_if_needed
|
522
|
+
self.currency = Spree::Store.default.default_currency if price.present? && currency.nil?
|
523
|
+
end
|
524
|
+
|
525
|
+
def infer_price_from_default_variant_if_needed
|
526
|
+
if price.nil?
|
527
|
+
return errors.add(:base, :no_master_variant_found_to_infer_price) unless product&.master
|
528
|
+
|
529
|
+
# At this point, master can have or have no price, so let's use price from the default variant
|
530
|
+
self.price = product.default_variant.price
|
397
531
|
end
|
398
532
|
end
|
399
533
|
|
@@ -411,12 +545,27 @@ module Spree
|
|
411
545
|
"variant-#{id}-in_stock"
|
412
546
|
end
|
413
547
|
|
414
|
-
def clear_in_stock_cache
|
415
|
-
Rails.cache.delete(in_stock_cache_key)
|
416
|
-
end
|
417
|
-
|
418
548
|
def disable_sku_validation?
|
419
549
|
Spree::Config[:disable_sku_validation]
|
420
550
|
end
|
551
|
+
|
552
|
+
def clear_line_items_cache
|
553
|
+
line_items.update_all(updated_at: Time.current)
|
554
|
+
end
|
555
|
+
|
556
|
+
def handle_track_inventory_change
|
557
|
+
return unless track_inventory_previously_changed?
|
558
|
+
return if track_inventory
|
559
|
+
|
560
|
+
stock_items.update_all(backorderable: true, count_on_hand: 0, updated_at: Time.current)
|
561
|
+
end
|
562
|
+
|
563
|
+
def remove_prices_from_master_variant
|
564
|
+
product.master.prices.delete_all if prices.exists?
|
565
|
+
end
|
566
|
+
|
567
|
+
def remove_stock_items_from_master_variant
|
568
|
+
product.master.stock_items.delete_all
|
569
|
+
end
|
421
570
|
end
|
422
571
|
end
|
data/app/models/spree/zone.rb
CHANGED
@@ -0,0 +1,145 @@
|
|
1
|
+
module Spree
|
2
|
+
module CSV
|
3
|
+
class OrderLineItemPresenter
|
4
|
+
HEADERS = [
|
5
|
+
'Number',
|
6
|
+
'Email',
|
7
|
+
'Status',
|
8
|
+
'Currency',
|
9
|
+
'Subtotal',
|
10
|
+
'Shipping',
|
11
|
+
'Taxes',
|
12
|
+
'Taxes included',
|
13
|
+
'Discount Used',
|
14
|
+
'Free Shipping',
|
15
|
+
'Discount',
|
16
|
+
'Discount Code',
|
17
|
+
'Store Credit amount',
|
18
|
+
'Total',
|
19
|
+
'Shipping method',
|
20
|
+
'Total weight',
|
21
|
+
'Payment Type Used',
|
22
|
+
'Product ID',
|
23
|
+
'Item Quantity',
|
24
|
+
'Item SKU',
|
25
|
+
'Item Name',
|
26
|
+
'Item Price',
|
27
|
+
'Item Total Discount',
|
28
|
+
'Item Total Price',
|
29
|
+
'Item requires shipping',
|
30
|
+
'Item taxbale',
|
31
|
+
'Item Vendor',
|
32
|
+
'Category lvl0',
|
33
|
+
'Category lvl1',
|
34
|
+
'Category lvl2',
|
35
|
+
'Category lvl3',
|
36
|
+
'Category lvl4',
|
37
|
+
'Billing Name',
|
38
|
+
'Billing Address 1',
|
39
|
+
'Billing Address 2',
|
40
|
+
'Billing Company',
|
41
|
+
'Billing City',
|
42
|
+
'Billing Zip',
|
43
|
+
'Billing State',
|
44
|
+
'Billing Country',
|
45
|
+
'Billing Phone',
|
46
|
+
'Shipping Name',
|
47
|
+
'Shipping Address 1',
|
48
|
+
'Shipping Address 2',
|
49
|
+
'Shipping Company',
|
50
|
+
'Shipping City',
|
51
|
+
'Shipping Zip',
|
52
|
+
'Shipping State',
|
53
|
+
'Shipping Country',
|
54
|
+
'Shipping Phone',
|
55
|
+
'Placed at',
|
56
|
+
'Shipped at',
|
57
|
+
'Cancelled at',
|
58
|
+
'Cancelled by',
|
59
|
+
'Notes'
|
60
|
+
].freeze
|
61
|
+
|
62
|
+
def initialize(order, line_item, index)
|
63
|
+
@order = order
|
64
|
+
@line_item = line_item
|
65
|
+
@index = index
|
66
|
+
end
|
67
|
+
|
68
|
+
attr_accessor :order, :line_item, :index
|
69
|
+
|
70
|
+
def call
|
71
|
+
[
|
72
|
+
order.number,
|
73
|
+
index.zero? ? order.email : nil,
|
74
|
+
index.zero? ? order.state : nil,
|
75
|
+
index.zero? ? order.currency : nil,
|
76
|
+
index.zero? ? order.item_total.to_f : nil,
|
77
|
+
index.zero? ? order.shipment_total.to_f : nil,
|
78
|
+
index.zero? ? order.tax_total.to_f : nil,
|
79
|
+
index.zero? ? order.included_tax_total.positive? : nil,
|
80
|
+
index.zero? ? (order.promo_total.negative? || line_item.promo_total.negative?) : nil,
|
81
|
+
index.zero? ? order.has_free_shipping? : nil,
|
82
|
+
index.zero? ? order.promo_total.abs : nil,
|
83
|
+
index.zero? ? order.promo_code : nil,
|
84
|
+
index.zero? ? order.payments.store_credits.sum(:amount).abs : nil,
|
85
|
+
index.zero? ? order.total.to_f : nil,
|
86
|
+
index.zero? ? order.shipping_method&.name : nil,
|
87
|
+
index.zero? ? order.total_weight.to_f : nil,
|
88
|
+
index.zero? && order.payments.valid.any? ? order.payments.valid.first.display_source_name : nil,
|
89
|
+
line_item.product_id,
|
90
|
+
line_item.quantity,
|
91
|
+
line_item.sku,
|
92
|
+
line_item.name,
|
93
|
+
line_item.price,
|
94
|
+
line_item.promo_total.abs,
|
95
|
+
line_item.total,
|
96
|
+
!line_item.product.digital?,
|
97
|
+
line_item.product.tax_category.present?,
|
98
|
+
line_item.product.try(:vendor_name),
|
99
|
+
taxon_dict(line_item.product.main_taxon)[0],
|
100
|
+
taxon_dict(line_item.product.main_taxon)[1],
|
101
|
+
taxon_dict(line_item.product.main_taxon)[2],
|
102
|
+
taxon_dict(line_item.product.main_taxon)[3],
|
103
|
+
taxon_dict(line_item.product.main_taxon)[4],
|
104
|
+
index.zero? ? order.bill_address&.full_name : nil,
|
105
|
+
index.zero? ? order.bill_address&.address1 : nil,
|
106
|
+
index.zero? ? order.bill_address&.address2 : nil,
|
107
|
+
index.zero? ? order.bill_address&.company : nil,
|
108
|
+
index.zero? ? order.bill_address&.city : nil,
|
109
|
+
index.zero? ? order.bill_address&.zipcode : nil,
|
110
|
+
index.zero? ? order.bill_address&.state_name : nil,
|
111
|
+
index.zero? ? order.bill_address&.country&.name : nil,
|
112
|
+
index.zero? ? order.bill_address&.phone : nil,
|
113
|
+
index.zero? ? order.ship_address&.full_name : nil,
|
114
|
+
index.zero? ? order.ship_address&.address1 : nil,
|
115
|
+
index.zero? ? order.ship_address&.address2 : nil,
|
116
|
+
index.zero? ? order.ship_address&.company : nil,
|
117
|
+
index.zero? ? order.ship_address&.city : nil,
|
118
|
+
index.zero? ? order.ship_address&.zipcode : nil,
|
119
|
+
index.zero? ? order.ship_address&.state_name : nil,
|
120
|
+
index.zero? ? order.ship_address&.country&.name : nil,
|
121
|
+
index.zero? ? order.ship_address&.phone : nil,
|
122
|
+
index.zero? ? format_date(order.completed_at) : nil,
|
123
|
+
format_date(line_item.order.shipments.first&.shipped_at),
|
124
|
+
index.zero? ? format_date(order.canceled_at) : nil,
|
125
|
+
index.zero? ? order.canceler&.email : nil,
|
126
|
+
index.zero? ? order.special_instructions : nil
|
127
|
+
]
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def taxon_dict(taxon)
|
133
|
+
return [] if taxon.blank?
|
134
|
+
|
135
|
+
taxon.pretty_name.to_s.split('->').map(&:strip)
|
136
|
+
end
|
137
|
+
|
138
|
+
def format_date(date)
|
139
|
+
return nil if date.blank?
|
140
|
+
|
141
|
+
date.in_time_zone(order.store.preferred_timezone).strftime('%Y-%m-%d %H:%M:%S')
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module CSV
|
5
|
+
class ProductPresenter
|
6
|
+
def initialize(product, properties = [], store = nil)
|
7
|
+
@product = product
|
8
|
+
@properties = properties
|
9
|
+
@store = store || product.stores.first
|
10
|
+
@currency = @store.default_currency
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :product, :properties, :store, :currency
|
14
|
+
|
15
|
+
def call
|
16
|
+
[
|
17
|
+
product.id,
|
18
|
+
product.try(:vendor_name),
|
19
|
+
product.try(:brand_name),
|
20
|
+
product.name,
|
21
|
+
product.description&.html_safe,
|
22
|
+
product.amount_in(currency).to_f,
|
23
|
+
product.meta_title,
|
24
|
+
product.meta_description,
|
25
|
+
product.meta_keywords,
|
26
|
+
product.tag_list.to_s,
|
27
|
+
product.label_list.to_s,
|
28
|
+
product.width,
|
29
|
+
product.height,
|
30
|
+
product.depth,
|
31
|
+
product.weight,
|
32
|
+
product.available_on&.strftime('%Y-%m-%d %H:%M:%S'),
|
33
|
+
product.discontinue_on&.strftime('%Y-%m-%d %H:%M:%S'),
|
34
|
+
product.status,
|
35
|
+
*map_categories(product),
|
36
|
+
product.total_on_hand == BigDecimal::INFINITY ? '∞' : product.total_on_hand,
|
37
|
+
*present_properties
|
38
|
+
]
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def map_categories(product)
|
44
|
+
categories = [nil, nil, nil]
|
45
|
+
|
46
|
+
product.taxons.reorder(depth: :desc).first(3).pluck(:pretty_name).each_with_index do |category_name, index|
|
47
|
+
categories[index] = category_name
|
48
|
+
end
|
49
|
+
|
50
|
+
categories
|
51
|
+
end
|
52
|
+
|
53
|
+
def present_properties
|
54
|
+
properties.flat_map do |property|
|
55
|
+
[
|
56
|
+
property.name,
|
57
|
+
product.property(property.name)
|
58
|
+
]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|