spree_core 6.0.0.beta3 → 6.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/README.md +2 -2
- data/app/helpers/spree/images_helper.rb +0 -57
- data/app/jobs/spree/base_job.rb +21 -0
- data/app/jobs/spree/carts/reap_expired_job.rb +2 -2
- data/app/jobs/spree/collections/regenerate_time_based_job.rb +6 -3
- data/app/jobs/spree/orders/finalize_stale_drafts_job.rb +8 -5
- data/app/jobs/spree/payments/cancel_unused_sessions_job.rb +61 -0
- data/app/jobs/spree/seller_payouts/sweep_seller_job.rb +2 -0
- data/app/mailers/spree/admin_user_mailer.rb +4 -19
- data/app/mailers/spree/base_mailer.rb +96 -13
- data/app/mailers/spree/email_template_mailer.rb +27 -0
- data/app/mailers/spree/export_mailer.rb +3 -4
- data/app/mailers/spree/import_mailer.rb +3 -4
- data/app/mailers/spree/invitation_mailer.rb +24 -7
- data/app/mailers/spree/seller_user_mailer.rb +4 -16
- data/app/mailers/spree/webhook_mailer.rb +2 -2
- data/app/models/concerns/spree/acted_by.rb +1 -1
- data/app/models/concerns/spree/admin_user_methods.rb +13 -1
- data/app/models/concerns/spree/api_typed.rb +91 -0
- data/app/models/concerns/spree/calculator/tiers.rb +76 -0
- data/app/models/concerns/spree/customer_methods.rb +15 -14
- data/app/models/concerns/spree/email_template_identity.rb +52 -0
- data/app/models/concerns/spree/parameterizable_name.rb +2 -0
- data/app/models/concerns/spree/payment_session_transitions.rb +8 -2
- data/app/models/concerns/spree/post_sale/taxation.rb +54 -0
- data/app/models/concerns/spree/post_sale/taxed_line.rb +51 -0
- data/app/models/concerns/spree/preference_schema.rb +4 -12
- data/app/models/concerns/spree/product_scopes.rb +11 -1
- data/app/models/concerns/spree/provider_listing.rb +41 -0
- data/app/models/concerns/spree/publishable.rb +82 -14
- data/app/models/concerns/spree/purchase/addresses.rb +23 -10
- data/app/models/concerns/spree/purchase/currency.rb +1 -1
- data/app/models/concerns/spree/purchase/deprecated_aliases.rb +87 -0
- data/app/models/concerns/spree/purchase/gift_cards.rb +10 -4
- data/app/models/concerns/spree/purchase/locale.rb +1 -1
- data/app/models/concerns/spree/purchase/payment_processing.rb +7 -3
- data/app/models/concerns/spree/purchase/purchase_order.rb +2 -2
- data/app/models/concerns/spree/purchase/totals.rb +49 -1
- data/app/models/concerns/spree/receivable.rb +1 -1
- data/app/models/concerns/spree/searchable.rb +0 -4
- data/app/models/concerns/spree/secret_preferences.rb +59 -0
- data/app/models/concerns/spree/single_store_resource.rb +1 -1
- data/app/models/concerns/spree/stores/email_branding.rb +31 -0
- data/app/models/concerns/spree/type_labels.rb +38 -0
- data/app/models/concerns/spree/typed_adjustment_line.rb +1 -1
- data/app/models/concerns/spree/typed_associations.rb +6 -0
- data/app/models/spree/address.rb +11 -1
- data/app/models/spree/adjusters/promotion.rb +1 -15
- data/app/models/spree/allowed_origin.rb +0 -1
- data/app/models/spree/api_key.rb +5 -6
- data/app/models/spree/authentication/strategies/oidc_strategy.rb +5 -5
- data/app/models/spree/base.rb +70 -22
- data/app/models/spree/calculator/flat_percent_item_total.rb +1 -3
- data/app/models/spree/calculator/flat_rate.rb +1 -3
- data/app/models/spree/calculator/flexi_rate.rb +1 -3
- data/app/models/spree/calculator/percent_on_line_item.rb +1 -1
- data/app/models/spree/calculator/price_sack.rb +1 -3
- data/app/models/spree/calculator/shipping/digital_delivery.rb +1 -3
- data/app/models/spree/calculator/shipping/flat_percent_item_total.rb +1 -3
- data/app/models/spree/calculator/shipping/flat_rate.rb +1 -3
- data/app/models/spree/calculator/shipping/flexi_rate.rb +1 -3
- data/app/models/spree/calculator/shipping/per_item.rb +1 -3
- data/app/models/spree/calculator/shipping/price_sack.rb +1 -3
- data/app/models/spree/calculator/tiered_flat_rate.rb +6 -23
- data/app/models/spree/calculator/tiered_percent.rb +7 -25
- data/app/models/spree/cart.rb +78 -18
- data/app/models/spree/channel/gating.rb +1 -1
- data/app/models/spree/channel.rb +4 -4
- data/app/models/spree/claim.rb +21 -1
- data/app/models/spree/claim_line_item.rb +41 -6
- data/app/models/spree/collection.rb +0 -1
- data/app/models/spree/collection_rule.rb +5 -21
- data/app/models/spree/commission_line.rb +1 -1
- data/app/models/spree/commission_rate.rb +2 -3
- data/app/models/spree/commission_rate_value.rb +1 -1
- data/app/models/spree/commission_rule.rb +4 -11
- data/app/models/spree/commission_rules/product_rule.rb +1 -1
- data/app/models/spree/company_invitation.rb +1 -0
- data/app/models/spree/consent_record.rb +0 -1
- data/app/models/spree/credit_card.rb +1 -1
- data/app/models/spree/current.rb +23 -0
- data/app/models/spree/custom_field.rb +2 -2
- data/app/models/spree/custom_field_definition.rb +9 -23
- data/app/models/spree/custom_fields/boolean.rb +1 -1
- data/app/models/spree/custom_fields/json.rb +1 -1
- data/app/models/spree/data_feed/google.rb +0 -2
- data/app/models/spree/data_request.rb +1 -1
- data/app/models/spree/delivery_method.rb +30 -13
- data/app/models/spree/delivery_method_rule.rb +4 -11
- data/app/models/spree/delivery_rate.rb +4 -5
- data/app/models/spree/delivery_rate_provider/base.rb +1 -0
- data/app/models/spree/delivery_zone.rb +0 -1
- data/app/models/spree/delivery_zone_member.rb +4 -4
- data/app/models/spree/digital_asset.rb +7 -0
- data/app/models/spree/digital_asset_provider/base.rb +2 -0
- data/app/models/spree/digital_link.rb +2 -5
- data/app/models/spree/discount.rb +1 -1
- data/app/models/spree/email_template.rb +25 -0
- data/app/models/spree/email_template_draft.rb +13 -0
- data/app/models/spree/email_template_revision.rb +17 -0
- data/app/models/spree/email_templates/entry.rb +118 -0
- data/app/models/spree/email_templates/sample_record.rb +16 -0
- data/app/models/spree/emails/branding.rb +80 -0
- data/app/models/spree/exchange.rb +15 -1
- data/app/models/spree/exchange_line_item.rb +121 -5
- data/app/models/spree/export.rb +0 -1
- data/app/models/spree/exports/products.rb +10 -1
- data/app/models/spree/exports/report.rb +1 -1
- data/app/models/spree/fee.rb +4 -2
- data/app/models/spree/fulfillment.rb +53 -27
- data/app/models/spree/fulfillment_changer.rb +2 -2
- data/app/models/spree/fulfillment_item.rb +0 -4
- data/app/models/spree/fulfillment_provider/base.rb +1 -0
- data/app/models/spree/gateway/bogus.rb +4 -0
- data/app/models/spree/gateway/custom_payment_source_method.rb +5 -0
- data/app/models/spree/gateway.rb +5 -1
- data/app/models/spree/gift_card.rb +12 -1
- data/app/models/spree/gift_card_batch.rb +0 -1
- data/app/models/spree/import.rb +2 -7
- data/app/models/spree/import_mapping.rb +1 -2
- data/app/models/spree/import_row.rb +2 -2
- data/app/models/spree/import_schemas/products.rb +1 -0
- data/app/models/spree/integration.rb +8 -18
- data/app/models/spree/invitation.rb +5 -5
- data/app/models/spree/line_item.rb +13 -2
- data/app/models/spree/locale.rb +11 -8
- data/app/models/spree/market.rb +1 -0
- data/app/models/spree/newsletter_subscriber.rb +3 -0
- data/app/models/spree/order.rb +56 -138
- data/app/models/spree/order_group.rb +11 -2
- data/app/models/spree/order_inventory.rb +10 -5
- data/app/models/spree/order_promotion.rb +1 -1
- data/app/models/spree/order_routing/has_strategy_preference.rb +1 -1
- data/app/models/spree/order_routing/strategy/base.rb +4 -2
- data/app/models/spree/order_routing/strategy/rules.rb +1 -1
- data/app/models/spree/order_routing_rule.rb +6 -22
- data/app/models/spree/package_type.rb +1 -2
- data/app/models/spree/payment/gateway_options.rb +14 -52
- data/app/models/spree/payment/processing.rb +2 -4
- data/app/models/spree/payment.rb +20 -5
- data/app/models/spree/payment_method/session_instrumentation.rb +1 -0
- data/app/models/spree/payment_method/store_credit.rb +4 -4
- data/app/models/spree/payment_method.rb +36 -4
- data/app/models/spree/payment_session.rb +5 -1
- data/app/models/spree/payment_setup_session.rb +1 -0
- data/app/models/spree/payout_provider/base.rb +3 -1
- data/app/models/spree/pickup_point_provider/base.rb +2 -0
- data/app/models/spree/price_list.rb +1 -2
- data/app/models/spree/price_rules/channel_rule.rb +1 -1
- data/app/models/spree/price_rules/customer_group_rule.rb +1 -1
- data/app/models/spree/product.rb +31 -7
- data/app/models/spree/product_submission.rb +0 -12
- data/app/models/spree/product_type.rb +0 -1
- data/app/models/spree/promotion/actions/create_line_items.rb +27 -17
- data/app/models/spree/promotion/rules/category.rb +0 -4
- data/app/models/spree/promotion/rules/channel.rb +0 -4
- data/app/models/spree/promotion/rules/country.rb +0 -4
- data/app/models/spree/promotion/rules/currency.rb +0 -4
- data/app/models/spree/promotion/rules/customer_group.rb +0 -4
- data/app/models/spree/promotion/rules/first_order.rb +0 -4
- data/app/models/spree/promotion/rules/item_total.rb +4 -8
- data/app/models/spree/promotion/rules/market.rb +0 -4
- data/app/models/spree/promotion/rules/one_use_per_user.rb +0 -4
- data/app/models/spree/promotion/rules/option_value.rb +0 -3
- data/app/models/spree/promotion/rules/product.rb +0 -4
- data/app/models/spree/promotion/rules/user.rb +0 -4
- data/app/models/spree/promotion/rules/user_logged_in.rb +0 -4
- data/app/models/spree/promotion.rb +35 -6
- data/app/models/spree/promotion_action.rb +7 -14
- data/app/models/spree/promotion_action_line_item.rb +1 -1
- data/app/models/spree/promotion_handler/coupon.rb +59 -27
- data/app/models/spree/promotion_rule.rb +7 -14
- data/app/models/spree/purchase_order.rb +1 -0
- data/app/models/spree/quantity_rule.rb +1 -1
- data/app/models/spree/refund.rb +28 -3
- data/app/models/spree/return.rb +30 -2
- data/app/models/spree/return_line_item.rb +65 -14
- data/app/models/spree/role.rb +7 -7
- data/app/models/spree/saved_report.rb +1 -1
- data/app/models/spree/seller.rb +2 -1
- data/app/models/spree/seller_payout.rb +7 -0
- data/app/models/spree/seller_requirement.rb +4 -12
- data/app/models/spree/seller_requirement_custom_field.rb +1 -2
- data/app/models/spree/seller_requirement_submission.rb +2 -2
- data/app/models/spree/seller_requirements/accept_terms.rb +2 -3
- data/app/models/spree/seller_transfer.rb +5 -0
- data/app/models/spree/shipping_label.rb +1 -0
- data/app/models/spree/stock/availability_validator.rb +2 -2
- data/app/models/spree/stock/inventory_unit_builder.rb +1 -1
- data/app/models/spree/stock/packer.rb +2 -2
- data/app/models/spree/stock/splitter/weight.rb +1 -1
- data/app/models/spree/stock_level/custom_events.rb +6 -0
- data/app/models/spree/stock_level.rb +1 -1
- data/app/models/spree/stock_movement.rb +1 -1
- data/app/models/spree/stock_receipt_item.rb +1 -1
- data/app/models/spree/stock_reservation.rb +2 -2
- data/app/models/spree/stock_transfer.rb +4 -2
- data/app/models/spree/store.rb +33 -7
- data/app/models/spree/store_credit.rb +8 -9
- data/app/models/spree/store_credit_event.rb +5 -5
- data/app/models/spree/tax_exemption_certificate.rb +2 -0
- data/app/models/spree/tax_identifier.rb +3 -1
- data/app/models/spree/tax_line.rb +53 -3
- data/app/models/spree/tax_provider/base.rb +71 -14
- data/app/models/spree/tax_provider/internal.rb +59 -33
- data/app/models/spree/tax_provider/recorded_share.rb +114 -0
- data/app/models/spree/tax_rate.rb +1 -2
- data/app/models/spree/taxonomy.rb +0 -1
- data/app/models/spree/variant.rb +4 -3
- data/app/models/spree/variant_media.rb +1 -1
- data/app/models/spree/webhook_endpoint.rb +10 -13
- data/app/models/spree/wishlist.rb +1 -6
- data/app/models/spree/wishlist_item/custom_events.rb +6 -0
- data/app/presenters/spree/csv/customer_presenter.rb +1 -1
- data/app/presenters/spree/csv/newsletter_subscriber_presenter.rb +1 -1
- data/app/presenters/spree/csv/order_line_item_presenter.rb +1 -1
- data/app/presenters/spree/csv/product_variant_presenter.rb +42 -12
- data/app/serializers/spree/emails/base_serializer.rb +14 -0
- data/app/serializers/spree/emails/export_serializer.rb +13 -0
- data/app/serializers/spree/emails/import_serializer.rb +19 -0
- data/app/serializers/spree/emails/invitation_serializer.rb +28 -0
- data/app/serializers/spree/emails/store_serializer.rb +31 -0
- data/app/serializers/spree/emails/user_serializer.rb +12 -0
- data/app/serializers/spree/emails/webhook_endpoint_serializer.rb +16 -0
- data/app/services/spree/carts/create.rb +8 -2
- data/app/services/spree/carts/destroy.rb +2 -2
- data/app/services/spree/carts/remove_out_of_stock_items.rb +2 -2
- data/app/services/spree/carts/split_by_seller.rb +1 -1
- data/app/services/spree/carts/update.rb +19 -5
- data/app/services/spree/catalogs/set_product_terms.rb +1 -1
- data/app/services/spree/categories/add_products.rb +13 -31
- data/app/services/spree/categories/remove_products.rb +12 -51
- data/app/services/spree/checkout/advance.rb +1 -4
- data/app/services/spree/collections/add_products.rb +10 -23
- data/app/services/spree/collections/remove_products.rb +7 -43
- data/app/services/spree/coupon_codes/bulk_generate.rb +8 -14
- data/app/services/spree/data_requests/create.rb +1 -1
- data/app/services/spree/deliveries/destroy.rb +2 -2
- data/app/services/spree/email_templates/check.rb +58 -0
- data/app/services/spree/email_templates/no_sample_record.rb +7 -0
- data/app/services/spree/email_templates/preview.rb +99 -0
- data/app/services/spree/emails/file_system.rb +23 -0
- data/app/services/spree/emails/filters.rb +84 -0
- data/app/services/spree/emails/liquid_context.rb +48 -0
- data/app/services/spree/emails/rendered_email.rb +14 -0
- data/app/services/spree/emails/renderer.rb +125 -0
- data/app/services/spree/emails/template.rb +51 -0
- data/app/services/spree/emails/template_data.rb +23 -0
- data/app/services/spree/emails/template_resolver.rb +109 -0
- data/app/services/spree/emails/text_converter.rb +72 -0
- data/app/services/spree/emails/translation_inliner.rb +134 -0
- data/app/services/spree/imports/row_processors/price_list_price.rb +10 -10
- data/app/services/spree/imports/row_processors/product_variant.rb +65 -34
- data/app/services/spree/imports/row_processors/purchase_order.rb +13 -13
- data/app/services/spree/locales.rb +4 -5
- data/app/services/spree/newsletter/subscribe.rb +8 -12
- data/app/services/spree/orders/build_fulfillments.rb +3 -2
- data/app/services/spree/orders/create.rb +2 -1
- data/app/services/spree/orders/discounts/create.rb +7 -4
- data/app/services/spree/orders/discounts/destroy.rb +1 -0
- data/app/services/spree/orders/discounts/update.rb +1 -0
- data/app/services/spree/orders/fees/create.rb +1 -0
- data/app/services/spree/orders/fees/destroy.rb +1 -0
- data/app/services/spree/orders/fees/update.rb +1 -0
- data/app/services/spree/orders/remove_line_item.rb +13 -3
- data/app/services/spree/orders/update.rb +10 -6
- data/app/services/spree/orders/update_item.rb +6 -3
- data/app/services/spree/orders/update_statuses.rb +3 -1
- data/app/services/spree/product_memberships.rb +61 -0
- data/app/services/spree/returns/eligibility_validator.rb +1 -1
- data/app/services/spree/search_provider/custom_field_schema.rb +2 -2
- data/app/services/spree/seeds/commission_rates.rb +1 -1
- data/app/services/spree/seeds/digital_delivery.rb +1 -1
- data/app/services/spree/seeds/payment_methods.rb +2 -2
- data/app/services/spree/seeds/saved_reports.rb +3 -3
- data/app/services/spree/sellers/requirements.rb +1 -2
- data/app/services/spree/shipping_labels/confirm_refund.rb +1 -1
- data/app/services/spree/shipping_labels/store_file.rb +3 -3
- data/app/services/spree/stock_levels/correct.rb +3 -3
- data/app/services/spree/stock_reservations/reserve.rb +2 -3
- data/app/services/spree/store_credits/apply.rb +15 -13
- data/app/services/spree/stores/provision_defaults.rb +15 -14
- data/app/subscribers/spree/seller_onboarding_subscriber.rb +1 -1
- data/app/views/layouts/spree/base_mailer.html.erb +2 -43
- data/app/views/layouts/spree/base_mailer.liquid +79 -0
- data/app/views/spree/admin_user_mailer/password_reset_email.liquid +14 -0
- data/app/views/spree/export_mailer/export_done.liquid +12 -0
- data/app/views/spree/import_mailer/import_done.liquid +15 -0
- data/app/views/spree/invitation_mailer/invitation_accepted.liquid +9 -0
- data/app/views/spree/invitation_mailer/invitation_email.liquid +13 -0
- data/app/views/spree/seller_user_mailer/password_reset_email.liquid +14 -0
- data/app/views/spree/shared/_mailer_button.html.erb +4 -5
- data/app/views/spree/shared/_mailer_hero.html.erb +6 -5
- data/app/views/spree/shared/_summary_row.liquid +8 -0
- data/app/views/spree/webhook_mailer/endpoint_disabled.liquid +21 -0
- data/app/workflows/spree/carts/add_item.rb +4 -4
- data/app/workflows/spree/carts/complete.rb +13 -3
- data/app/workflows/spree/carts/merge.rb +1 -1
- data/app/workflows/spree/carts/recalculate_totals.rb +5 -0
- data/app/workflows/spree/carts/upsert_items.rb +18 -9
- data/app/workflows/spree/claims/approve.rb +5 -22
- data/app/workflows/spree/claims/cancel.rb +5 -21
- data/app/workflows/spree/claims/create.rb +15 -0
- data/app/workflows/spree/claims/deny.rb +7 -0
- data/app/workflows/spree/claims/resolve.rb +34 -31
- data/app/workflows/spree/customers/anonymize.rb +3 -4
- data/app/workflows/spree/customers/create.rb +1 -1
- data/app/workflows/spree/data_requests/fulfill.rb +2 -2
- data/app/workflows/spree/deliveries/update_tracking.rb +1 -1
- data/app/workflows/spree/email_templates/discard_draft.rb +20 -0
- data/app/workflows/spree/email_templates/publish.rb +70 -0
- data/app/workflows/spree/email_templates/restore_revision.rb +33 -0
- data/app/workflows/spree/email_templates/revert.rb +29 -0
- data/app/workflows/spree/email_templates/save_draft.rb +85 -0
- data/app/workflows/spree/exchanges/approve.rb +5 -22
- data/app/workflows/spree/exchanges/cancel.rb +5 -21
- data/app/workflows/spree/exchanges/create.rb +6 -0
- data/app/workflows/spree/exchanges/fulfill.rb +75 -51
- data/app/workflows/spree/exchanges/receive.rb +6 -65
- data/app/workflows/spree/fulfillments/cancel.rb +1 -1
- data/app/workflows/spree/fulfillments/create.rb +51 -47
- data/app/workflows/spree/fulfillments/fulfill.rb +23 -27
- data/app/workflows/spree/fulfillments/mark_delivered.rb +1 -1
- data/app/workflows/spree/fulfillments/replacements.rb +59 -0
- data/app/workflows/spree/gift_cards/apply.rb +2 -2
- data/app/workflows/spree/orders/add_item.rb +5 -1
- data/app/workflows/spree/orders/cancel.rb +3 -3
- data/app/workflows/spree/orders/complete.rb +16 -8
- data/app/workflows/spree/payments/process.rb +2 -2
- data/app/workflows/spree/post_sale/approval.rb +35 -0
- data/app/workflows/spree/post_sale/cancellation.rb +44 -0
- data/app/workflows/spree/post_sale/receipt.rb +92 -0
- data/app/workflows/spree/products/nested_attributes.rb +1 -1
- data/app/workflows/spree/purchase_orders/cancel.rb +1 -1
- data/app/workflows/spree/purchase_orders/close.rb +3 -31
- data/app/workflows/spree/purchase_orders/mark_draft.rb +2 -2
- data/app/workflows/spree/purchase_orders/mark_ordered.rb +2 -2
- data/app/workflows/spree/purchase_orders/receive.rb +1 -1
- data/app/workflows/spree/purchase_orders/update.rb +5 -34
- data/app/workflows/spree/receivables/closing_short.rb +46 -0
- data/app/workflows/spree/receivables/draft_editing.rb +48 -0
- data/app/workflows/spree/refunds/create.rb +5 -2
- data/app/workflows/spree/refunds/order_payments.rb +14 -2
- data/app/workflows/spree/refunds/tax_credit.rb +67 -0
- data/app/workflows/spree/returns/approve.rb +5 -22
- data/app/workflows/spree/returns/cancel.rb +5 -22
- data/app/workflows/spree/returns/create.rb +8 -0
- data/app/workflows/spree/returns/receive.rb +5 -76
- data/app/workflows/spree/returns/refund.rb +31 -8
- data/app/workflows/spree/seller_requirement_submissions/create.rb +1 -2
- data/app/workflows/spree/seller_transfers/reverse.rb +28 -1
- data/app/workflows/spree/shipping_labels/purchase.rb +8 -8
- data/app/workflows/spree/shipping_labels/record.rb +5 -5
- data/app/workflows/spree/shipping_labels/refund.rb +2 -2
- data/app/workflows/spree/stock_receipts/recording.rb +4 -4
- data/app/workflows/spree/stock_transfers/cancel.rb +2 -2
- data/app/workflows/spree/stock_transfers/close.rb +3 -30
- data/app/workflows/spree/stock_transfers/mark_draft.rb +1 -1
- data/app/workflows/spree/stock_transfers/mark_in_transit.rb +3 -3
- data/app/workflows/spree/stock_transfers/mark_ready.rb +2 -2
- data/app/workflows/spree/stock_transfers/receive.rb +1 -1
- data/app/workflows/spree/stock_transfers/update.rb +5 -33
- data/config/i18n-tasks.yml +32 -18
- data/config/initializers/alba.rb +7 -0
- data/config/language_names.csv +264 -0
- data/config/locales/ar.yml +811 -0
- data/config/locales/be.yml +855 -0
- data/config/locales/bg.yml +723 -0
- data/config/locales/ca.yml +689 -0
- data/config/locales/cs.yml +855 -0
- data/config/locales/da.yml +771 -0
- data/config/locales/de-CH.yml +248 -0
- data/config/locales/de.yml +835 -0
- data/config/locales/el.yml +769 -0
- data/config/locales/en.yml +37 -503
- data/config/locales/es-CL.yml +301 -0
- data/config/locales/es-EC.yml +186 -0
- data/config/locales/es-MX.yml +334 -0
- data/config/locales/es.yml +831 -0
- data/config/locales/et.yml +644 -0
- data/config/locales/fa.yml +709 -0
- data/config/locales/fi.yml +771 -0
- data/config/locales/fr.yml +830 -0
- data/config/locales/hu.yml +751 -0
- data/config/locales/id.yml +756 -0
- data/config/locales/it.yml +833 -0
- data/config/locales/ja.yml +726 -0
- data/config/locales/km.yml +759 -0
- data/config/locales/ko.yml +575 -0
- data/config/locales/ku.yml +753 -0
- data/config/locales/lt.yml +821 -0
- data/config/locales/lv.yml +685 -0
- data/config/locales/nb.yml +824 -0
- data/config/locales/ne.yml +823 -0
- data/config/locales/nl.yml +826 -0
- data/config/locales/pl.yml +835 -0
- data/config/locales/pt-BR.yml +547 -0
- data/config/locales/pt.yml +636 -0
- data/config/locales/ro.yml +750 -0
- data/config/locales/ru.yml +834 -0
- data/config/locales/sk.yml +680 -0
- data/config/locales/sl-SI.yml +600 -0
- data/config/locales/sv.yml +827 -0
- data/config/locales/th.yml +745 -0
- data/config/locales/tr.yml +777 -0
- data/config/locales/uk.yml +836 -0
- data/config/locales/vi.yml +768 -0
- data/config/locales/zh-CN.yml +786 -0
- data/config/locales/zh-TW.yml +834 -0
- data/db/migrate/20260925000001_add_replacement_to_spree_fulfillment_items.rb +5 -0
- data/db/migrate/20261001000001_add_post_sale_tax.rb +30 -0
- data/db/migrate/20261001000001_convert_preferences_to_json.rb +166 -0
- data/db/migrate/20261001000001_create_spree_email_templates.rb +52 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +0 -9
- data/lib/generators/spree/dummy/templates/rails/test.rb +7 -0
- data/lib/spree/checkout/default_requirements.rb +37 -13
- data/lib/spree/core/configuration.rb +1 -1
- data/lib/spree/core/controller_helpers/store.rb +1 -1
- data/lib/spree/core/dependencies.rb +5 -4
- data/lib/spree/core/emails/escaped_output.rb +60 -0
- data/lib/spree/core/engine.rb +48 -167
- data/lib/spree/core/permissions/default_catalog.rb +5 -0
- data/lib/spree/core/preferences/json_conversion.rb +182 -0
- data/lib/spree/core/preferences/masking.rb +4 -1
- data/lib/spree/core/preferences/preferable.rb +137 -83
- data/lib/spree/core/preferences/preferable_class_methods.rb +81 -146
- data/lib/spree/core/previews/import_preview.rb +10 -0
- data/lib/spree/core/tax/provider_error.rb +37 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +85 -370
- data/lib/spree/emails/editable_templates.rb +82 -0
- data/lib/spree/events/catalog.rb +189 -0
- data/lib/spree/events.rb +21 -1
- data/lib/spree/hooks.rb +0 -17
- data/lib/spree/i18n.rb +32 -15
- data/lib/spree/reporting/adapters/live.rb +6 -6
- data/lib/spree/reporting/default_vocabulary.rb +22 -10
- data/lib/spree/reporting/hydration.rb +1 -1
- data/lib/spree/reporting/query.rb +8 -0
- data/lib/spree/reporting/schema.rb +10 -10
- data/lib/spree/testing_support/editable_email_templates.rb +61 -0
- data/lib/spree/testing_support/emails.rb +22 -0
- data/lib/spree/testing_support/factories/cart_factory.rb +1 -1
- data/lib/spree/testing_support/factories/email_template_factory.rb +28 -0
- data/lib/spree/testing_support/factories/order_factory.rb +2 -2
- data/lib/spree/testing_support/factories/refund_factory.rb +1 -1
- data/lib/spree/testing_support/factories/stock_factory.rb +1 -1
- data/lib/spree/testing_support/factories/variant_factory.rb +1 -1
- data/lib/spree/testing_support/i18n.rb +3 -94
- data/lib/spree/testing_support/lifecycle_events.rb +1 -1
- data/lib/spree/testing_support/order_walkthrough.rb +1 -1
- data/lib/spree/testing_support/preferences.rb +0 -5
- data/lib/spree/testing_support/store.rb +9 -1
- data/lib/spree/upgrades/5_6_to_6_0/manifest.yml +45 -0
- data/lib/tasks/categories_and_collections.rake +3 -3
- data/lib/tasks/core.rake +6 -4
- data/lib/tasks/media.rake +3 -3
- data/lib/tasks/package_types.rake +1 -1
- data/lib/tasks/preferences_json.rake +101 -0
- data/spec/fixtures/mailer_views/custom_views_probe_mailer/welcome_email.html.erb +4 -0
- metadata +188 -44
- data/app/models/acts_as_taggable_on/tag_decorator.rb +0 -10
- data/app/models/concerns/spree/has_image_alt_text.rb +0 -18
- data/app/models/spree/base_analytics_event_handler.rb +0 -54
- data/app/models/spree/invitations/store.rb +0 -6
- data/app/models/spree/preference.rb +0 -14
- data/app/models/spree/promotion_handler/page.rb +0 -25
- data/app/models/spree/promotion_handler/promotion_duplicator.rb +0 -60
- data/app/models/spree/stock/differentiator.rb +0 -45
- data/app/presenters/spree/filters/options_presenter.rb +0 -47
- data/app/services/spree/carts/empty.rb +0 -42
- data/app/services/spree/country_to_timezone.rb +0 -273
- data/app/services/spree/payments/create.rb +0 -92
- data/app/validators/spree/url_validator.rb +0 -23
- data/app/views/active_storage/blobs/_blob.html.erb +0 -14
- data/app/views/spree/admin_user_mailer/password_reset_email.html.erb +0 -8
- data/app/views/spree/export_mailer/export_done.html.erb +0 -7
- data/app/views/spree/import_mailer/import_done.html.erb +0 -12
- data/app/views/spree/invitation_mailer/invitation_accepted.html.erb +0 -4
- data/app/views/spree/invitation_mailer/invitation_email.html.erb +0 -12
- data/app/views/spree/seller_user_mailer/password_reset_email.html.erb +0 -8
- data/app/views/spree/shared/_base_mailer_footer.html.erb +0 -19
- data/app/views/spree/shared/_base_mailer_header.html.erb +0 -8
- data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +0 -399
- data/app/views/spree/shared/_mailer_logo.html.erb +0 -41
- data/app/views/spree/shared/_purchased_items_styles.html.erb +0 -119
- data/app/views/spree/webhook_mailer/endpoint_disabled.html.erb +0 -51
- data/app/views/spree/webhook_mailer/endpoint_disabled.text.erb +0 -10
- data/app/workflows/spree/fulfillments/purchase_label.rb +0 -40
- data/app/workflows/spree/returns/purchase_label.rb +0 -32
- data/lib/spree/analytics.rb +0 -11
- data/lib/spree/core/preferences/scoped_store.rb +0 -34
- data/lib/spree/core/preferences/store.rb +0 -105
- data/lib/spree/translation_migrations.rb +0 -52
data/app/models/spree/base.rb
CHANGED
|
@@ -23,24 +23,20 @@ class Spree::Base < ApplicationRecord
|
|
|
23
23
|
# rather than assigning, so extensions don't clobber each other.
|
|
24
24
|
class_attribute :additional_permitted_attributes, instance_writer: false, default: [].freeze
|
|
25
25
|
|
|
26
|
+
# The Seller API's counterpart, kept separate because sellers write a
|
|
27
|
+
# narrower set than operators: an attribute an extension makes writable for
|
|
28
|
+
# admins stays admin-only unless it is also declared here.
|
|
29
|
+
#
|
|
30
|
+
# Spree::Product.additional_seller_permitted_attributes += [:brand_id]
|
|
31
|
+
class_attribute :additional_seller_permitted_attributes, instance_writer: false, default: [].freeze
|
|
32
|
+
|
|
26
33
|
# Backfills preferences added to the class after this row was last saved, so
|
|
27
|
-
# a reader never sees nil for a newly defined preference.
|
|
28
|
-
# unconditionally would dirty every record on load
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
# `with_lock` refuse the record ("unpersisted changes").
|
|
34
|
+
# a reader never sees nil for a newly defined preference. Only missing keys
|
|
35
|
+
# are assigned: assigning unconditionally would dirty every record on load,
|
|
36
|
+
# which is enough to make `with_lock` refuse the record ("unpersisted
|
|
37
|
+
# changes").
|
|
32
38
|
after_initialize do
|
|
33
|
-
if has_attribute?(:preferences) && !preferences.nil?
|
|
34
|
-
missing = default_preferences.except(*preferences.keys)
|
|
35
|
-
self.preferences = preferences.merge(missing) if missing.any?
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# only for backwards compatibility with Kaminari
|
|
40
|
-
if defined?(Kaminari) && Kaminari.config.page_method_name != :page
|
|
41
|
-
def self.page(num)
|
|
42
|
-
send Kaminari.config.page_method_name, num
|
|
43
|
-
end
|
|
39
|
+
backfill_default_preferences if has_attribute?(:preferences) && !preferences.nil?
|
|
44
40
|
end
|
|
45
41
|
|
|
46
42
|
self.abstract_class = true
|
|
@@ -115,9 +111,10 @@ class Spree::Base < ApplicationRecord
|
|
|
115
111
|
# read through the parent (a plain `Spree::Export` row, a factory that sets
|
|
116
112
|
# `type` as an attribute, a query on the base relation).
|
|
117
113
|
#
|
|
118
|
-
# Resolves against
|
|
119
|
-
# unrecognized column value
|
|
120
|
-
# constantized
|
|
114
|
+
# Resolves against the class's type registry where it has one, so an
|
|
115
|
+
# unrecognized column value (an extension no longer installed) is never
|
|
116
|
+
# constantized — it is shortened the same way instead, never sent as a class
|
|
117
|
+
# name.
|
|
121
118
|
#
|
|
122
119
|
# @param type [String, nil] value of the STI `type` column
|
|
123
120
|
# @return [String]
|
|
@@ -125,9 +122,33 @@ class Spree::Base < ApplicationRecord
|
|
|
125
122
|
return api_type if type.blank?
|
|
126
123
|
|
|
127
124
|
type = type.to_s
|
|
128
|
-
|
|
125
|
+
api_type_registry.find { |klass| klass.to_s == type }&.api_type || type.demodulize.underscore
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Inverse of {.api_type_for}: the STI `type` column value for a wire
|
|
129
|
+
# shorthand, or nil when no registered subclass answers to it. Lookup is
|
|
130
|
+
# registry-driven, so a request can never name a class outside the family.
|
|
131
|
+
#
|
|
132
|
+
# @param api_type [String, nil] e.g. `"orders"`
|
|
133
|
+
# @return [String, nil] e.g. `"Spree::Exports::Orders"`
|
|
134
|
+
def self.class_name_for_api_type(api_type)
|
|
135
|
+
return nil if api_type.blank?
|
|
129
136
|
|
|
130
|
-
|
|
137
|
+
api_type_registry.find { |klass| klass.api_type == api_type.to_s }&.to_s
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# The subclasses a typed family accepts — `registered_subclasses` for the
|
|
141
|
+
# preference-schema families, `available_types` for exports and imports.
|
|
142
|
+
#
|
|
143
|
+
# @return [Array<Class>]
|
|
144
|
+
def self.api_type_registry
|
|
145
|
+
if subclass_registry
|
|
146
|
+
registered_subclasses
|
|
147
|
+
elsif respond_to?(:available_types)
|
|
148
|
+
Array(available_types)
|
|
149
|
+
else
|
|
150
|
+
[]
|
|
151
|
+
end
|
|
131
152
|
end
|
|
132
153
|
|
|
133
154
|
# Shorthand for a *polymorphic* `*_type` column (`owner_type`,
|
|
@@ -138,10 +159,37 @@ class Spree::Base < ApplicationRecord
|
|
|
138
159
|
#
|
|
139
160
|
# @param type [String, Class, nil] value of the polymorphic type column
|
|
140
161
|
# @return [String, nil]
|
|
162
|
+
#
|
|
163
|
+
# The configured customer and admin user classes always answer `customer`
|
|
164
|
+
# and `admin_user`, so a host app's own `User` class does not change the
|
|
165
|
+
# contract.
|
|
141
166
|
def self.polymorphic_api_type(type)
|
|
142
167
|
return nil if type.blank?
|
|
143
168
|
|
|
144
|
-
type.to_s
|
|
169
|
+
type = type.to_s
|
|
170
|
+
return 'customer' if type == Spree.customer_class(constantize: false)
|
|
171
|
+
return 'admin_user' if type == Spree.admin_user_class(constantize: false)
|
|
172
|
+
|
|
173
|
+
type.demodulize.underscore
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Inverse of {.polymorphic_api_type}: the class name a polymorphic `*_type`
|
|
177
|
+
# column stores for a wire shorthand. Matches against `candidates` when the
|
|
178
|
+
# caller knows what the column may reference (always prefer that); otherwise
|
|
179
|
+
# against the configured customer and admin user classes, then the
|
|
180
|
+
# `Spree::` model of that name. Never constantizes the input.
|
|
181
|
+
#
|
|
182
|
+
# @param api_type [String, nil] e.g. `"purchase_order"`
|
|
183
|
+
# @param candidates [Array<Class, String>, nil] classes the column may hold
|
|
184
|
+
# @return [String, nil] e.g. `"Spree::PurchaseOrder"`
|
|
185
|
+
def self.polymorphic_type_for(api_type, candidates = nil)
|
|
186
|
+
token = api_type.to_s
|
|
187
|
+
return nil unless token.match?(/\A[a-z][a-z0-9_]*\z/)
|
|
188
|
+
|
|
189
|
+
candidates ||= [Spree.customer_class(constantize: false),
|
|
190
|
+
Spree.admin_user_class(constantize: false),
|
|
191
|
+
"Spree::#{token.camelize}"]
|
|
192
|
+
candidates.map(&:to_s).find { |name| polymorphic_api_type(name) == token }
|
|
145
193
|
end
|
|
146
194
|
|
|
147
195
|
# Prefixed id for a polymorphic reference, encoded from the columns without
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
require_dependency 'spree/calculator'
|
|
2
|
-
|
|
3
1
|
module Spree
|
|
4
2
|
class Calculator::FlatPercentItemTotal < Calculator
|
|
5
3
|
preference :flat_percent, :decimal, default: 0
|
|
6
4
|
|
|
7
5
|
def self.description
|
|
8
|
-
|
|
6
|
+
I18n.t('spree.flat_percent')
|
|
9
7
|
end
|
|
10
8
|
|
|
11
9
|
def compute(object)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require_dependency 'spree/calculator'
|
|
2
|
-
|
|
3
1
|
module Spree
|
|
4
2
|
class Calculator::FlatRate < Calculator
|
|
5
3
|
preference :amount, :decimal, default: 0
|
|
@@ -7,7 +5,7 @@ module Spree
|
|
|
7
5
|
preference :apply_only_on_full_priced_items, :boolean, default: false
|
|
8
6
|
|
|
9
7
|
def self.description
|
|
10
|
-
|
|
8
|
+
I18n.t('spree.flat_rate_per_order')
|
|
11
9
|
end
|
|
12
10
|
|
|
13
11
|
def compute(object = nil)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require_dependency 'spree/calculator'
|
|
2
|
-
|
|
3
1
|
module Spree
|
|
4
2
|
class Calculator::FlexiRate < Calculator
|
|
5
3
|
preference :first_item, :decimal, default: 0.0
|
|
@@ -9,7 +7,7 @@ module Spree
|
|
|
9
7
|
preference :apply_only_on_full_priced_items, :boolean, default: false
|
|
10
8
|
|
|
11
9
|
def self.description
|
|
12
|
-
|
|
10
|
+
I18n.t('spree.flexible_rate')
|
|
13
11
|
end
|
|
14
12
|
|
|
15
13
|
def self.available?(_object)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require_dependency 'spree/calculator'
|
|
2
|
-
|
|
3
1
|
module Spree
|
|
4
2
|
class Calculator::PriceSack < Calculator
|
|
5
3
|
preference :minimal_amount, :decimal, default: 0
|
|
@@ -8,7 +6,7 @@ module Spree
|
|
|
8
6
|
preference :currency, :string, default: -> { Spree::Store.default.default_currency }
|
|
9
7
|
|
|
10
8
|
def self.description
|
|
11
|
-
|
|
9
|
+
I18n.t('spree.price_sack')
|
|
12
10
|
end
|
|
13
11
|
|
|
14
12
|
# as object we always get line items, as calculable we have Coupon, ShippingMethod
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require_dependency 'spree/shipping_calculator'
|
|
2
|
-
|
|
3
1
|
module Spree
|
|
4
2
|
module Calculator::Shipping
|
|
5
3
|
class DigitalDelivery < ShippingCalculator
|
|
@@ -9,7 +7,7 @@ module Spree
|
|
|
9
7
|
preference :currency, :string, default: -> { Spree::Store.default.default_currency }
|
|
10
8
|
|
|
11
9
|
def self.description
|
|
12
|
-
|
|
10
|
+
I18n.t('spree.digital.digital_delivery')
|
|
13
11
|
end
|
|
14
12
|
|
|
15
13
|
def compute_package(package = nil)
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
require_dependency 'spree/shipping_calculator'
|
|
2
|
-
|
|
3
1
|
module Spree
|
|
4
2
|
module Calculator::Shipping
|
|
5
3
|
class FlatPercentItemTotal < ShippingCalculator
|
|
6
4
|
preference :flat_percent, :decimal, default: 0
|
|
7
5
|
|
|
8
6
|
def self.description
|
|
9
|
-
|
|
7
|
+
I18n.t('spree.flat_percent')
|
|
10
8
|
end
|
|
11
9
|
|
|
12
10
|
def compute_package(package)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require_dependency 'spree/shipping_calculator'
|
|
2
|
-
|
|
3
1
|
module Spree
|
|
4
2
|
module Calculator::Shipping
|
|
5
3
|
class FlatRate < ShippingCalculator
|
|
@@ -18,7 +16,7 @@ module Spree
|
|
|
18
16
|
preference :maximum_weight, :decimal, default: nil, nullable: true, deprecated: 'Use a Spree::DeliveryMethodRules rule on the delivery method instead; removed in Spree 6.1.'
|
|
19
17
|
|
|
20
18
|
def self.description
|
|
21
|
-
|
|
19
|
+
I18n.t('spree.shipping_flat_rate_per_order')
|
|
22
20
|
end
|
|
23
21
|
|
|
24
22
|
def compute_package(package)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require_dependency 'spree/shipping_calculator'
|
|
2
|
-
|
|
3
1
|
module Spree
|
|
4
2
|
module Calculator::Shipping
|
|
5
3
|
class FlexiRate < ShippingCalculator
|
|
@@ -15,7 +13,7 @@ module Spree
|
|
|
15
13
|
end
|
|
16
14
|
|
|
17
15
|
def self.description
|
|
18
|
-
|
|
16
|
+
I18n.t('spree.shipping_flexible_rate')
|
|
19
17
|
end
|
|
20
18
|
|
|
21
19
|
def compute_package(package)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require_dependency 'spree/shipping_calculator'
|
|
2
|
-
|
|
3
1
|
module Spree
|
|
4
2
|
module Calculator::Shipping
|
|
5
3
|
class PerItem < ShippingCalculator
|
|
@@ -9,7 +7,7 @@ module Spree
|
|
|
9
7
|
preference :currency, :string, default: -> { Spree::Store.default.default_currency }
|
|
10
8
|
|
|
11
9
|
def self.description
|
|
12
|
-
|
|
10
|
+
I18n.t('spree.shipping_flat_rate_per_item')
|
|
13
11
|
end
|
|
14
12
|
|
|
15
13
|
def compute_package(package)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require_dependency 'spree/shipping_calculator'
|
|
2
|
-
|
|
3
1
|
module Spree
|
|
4
2
|
module Calculator::Shipping
|
|
5
3
|
class PriceSack < ShippingCalculator
|
|
@@ -15,7 +13,7 @@ module Spree
|
|
|
15
13
|
end
|
|
16
14
|
|
|
17
15
|
def self.description
|
|
18
|
-
|
|
16
|
+
I18n.t('spree.shipping_price_sack')
|
|
19
17
|
end
|
|
20
18
|
|
|
21
19
|
def compute_package(package)
|
|
@@ -1,42 +1,25 @@
|
|
|
1
|
-
require_dependency 'spree/calculator'
|
|
2
|
-
|
|
3
1
|
module Spree
|
|
4
2
|
class Calculator::TieredFlatRate < Calculator
|
|
3
|
+
include Spree::Calculator::Tiers
|
|
4
|
+
|
|
5
5
|
preference :base_amount, :decimal, default: 0
|
|
6
6
|
preference :currency, :string, default: -> { Spree::Store.default.default_currency }
|
|
7
|
-
preference :tiers, :hash, default: {}
|
|
8
|
-
|
|
9
|
-
before_validation do
|
|
10
|
-
# Convert tier values to decimals. Strings don't do us much good.
|
|
11
|
-
if preferred_tiers.is_a?(Hash)
|
|
12
|
-
self.preferred_tiers = Hash[*preferred_tiers.flatten.map(&:to_f)]
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
validate :preferred_tiers_content
|
|
17
7
|
|
|
18
8
|
def self.description
|
|
19
|
-
|
|
9
|
+
I18n.t('spree.tiered_flat_rate')
|
|
20
10
|
end
|
|
21
11
|
|
|
22
12
|
def compute(object = nil)
|
|
23
13
|
return 0 unless object&.currency.present?
|
|
24
14
|
return 0 unless preferred_currency.casecmp(object.currency.upcase).zero?
|
|
25
15
|
|
|
26
|
-
|
|
27
|
-
amount || preferred_base_amount
|
|
16
|
+
tier_value_for(object.amount) || preferred_base_amount
|
|
28
17
|
end
|
|
29
18
|
|
|
30
19
|
private
|
|
31
20
|
|
|
32
|
-
def
|
|
33
|
-
|
|
34
|
-
unless preferred_tiers.keys.all? { |k| k.is_a?(Numeric) && k > 0 }
|
|
35
|
-
errors.add(:base, :keys_should_be_positive_number)
|
|
36
|
-
end
|
|
37
|
-
else
|
|
38
|
-
errors.add(:preferred_tiers, :should_be_hash)
|
|
39
|
-
end
|
|
21
|
+
def validate_tier_values(values)
|
|
22
|
+
errors.add(:preferred_tiers, :values_should_be_number) unless values.all? { |value| value && value >= 0 }
|
|
40
23
|
end
|
|
41
24
|
end
|
|
42
25
|
end
|
|
@@ -1,45 +1,27 @@
|
|
|
1
|
-
require_dependency 'spree/calculator'
|
|
2
|
-
|
|
3
1
|
module Spree
|
|
4
2
|
class Calculator::TieredPercent < Calculator
|
|
5
|
-
|
|
6
|
-
preference :tiers, :hash, default: {}
|
|
3
|
+
include Spree::Calculator::Tiers
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
# Convert tier values to decimals. Strings don't do us much good.
|
|
10
|
-
if preferred_tiers.is_a?(Hash)
|
|
11
|
-
self.preferred_tiers = Hash[*preferred_tiers.flatten.map(&:to_f)]
|
|
12
|
-
end
|
|
13
|
-
end
|
|
5
|
+
preference :base_percent, :decimal, default: 0
|
|
14
6
|
|
|
15
7
|
validates :preferred_base_percent, numericality: {
|
|
16
8
|
greater_than_or_equal_to: 0,
|
|
17
9
|
less_than_or_equal_to: 100
|
|
18
10
|
}
|
|
19
|
-
validate :preferred_tiers_content
|
|
20
11
|
|
|
21
12
|
def self.description
|
|
22
|
-
|
|
13
|
+
I18n.t('spree.tiered_percent')
|
|
23
14
|
end
|
|
24
15
|
|
|
25
16
|
def compute(object)
|
|
26
|
-
|
|
27
|
-
(object.amount *
|
|
17
|
+
percent = tier_value_for(object.amount) || preferred_base_percent
|
|
18
|
+
(object.amount * percent / 100).round(2)
|
|
28
19
|
end
|
|
29
20
|
|
|
30
21
|
private
|
|
31
22
|
|
|
32
|
-
def
|
|
33
|
-
|
|
34
|
-
unless preferred_tiers.keys.all? { |k| k.is_a?(Numeric) && k > 0 }
|
|
35
|
-
errors.add(:base, :keys_should_be_positive_number)
|
|
36
|
-
end
|
|
37
|
-
unless preferred_tiers.values.all? { |k| k.is_a?(Numeric) && k >= 0 && k <= 100 }
|
|
38
|
-
errors.add(:base, :values_should_be_percent)
|
|
39
|
-
end
|
|
40
|
-
else
|
|
41
|
-
errors.add(:preferred_tiers, :should_be_hash)
|
|
42
|
-
end
|
|
23
|
+
def validate_tier_values(values)
|
|
24
|
+
errors.add(:preferred_tiers, :values_should_be_percent) unless values.all? { |value| value&.between?(0, 100) }
|
|
43
25
|
end
|
|
44
26
|
end
|
|
45
27
|
end
|
data/app/models/spree/cart.rb
CHANGED
|
@@ -36,6 +36,7 @@ module Spree
|
|
|
36
36
|
include Spree::Purchase::Validations
|
|
37
37
|
include Spree::Purchase::Totals
|
|
38
38
|
include Spree::Purchase::Lifecycle
|
|
39
|
+
include Spree::Purchase::DeprecatedAliases
|
|
39
40
|
|
|
40
41
|
# Concurrency is manual (the API's OrderLock semantics — compare
|
|
41
42
|
# client-sent version, 409 on mismatch); Rails auto-locking must not
|
|
@@ -54,16 +55,7 @@ module Spree
|
|
|
54
55
|
:discount_total, :fee_total, :delivery_total, :total, :payment_total, :outstanding_balance,
|
|
55
56
|
:tax_total, :pre_tax_item_amount, :pre_tax_total, :amount_due
|
|
56
57
|
|
|
57
|
-
alias display_promo_total display_discount_total
|
|
58
|
-
alias display_ship_total display_delivery_total
|
|
59
|
-
alias_attribute :ship_total, :delivery_total
|
|
60
|
-
|
|
61
58
|
belongs_to :customer, class_name: "::#{Spree.customer_class}", optional: true
|
|
62
|
-
# Order-parity aliases — shared Cart/Order code (services, Purchase
|
|
63
|
-
# concerns) reads #user; the cart column is customer_id.
|
|
64
|
-
alias_method :user, :customer
|
|
65
|
-
alias_method :user=, :customer=
|
|
66
|
-
alias_attribute :user_id, :customer_id
|
|
67
59
|
# Codes are stored stripped + lowercased so lookups stay case-insensitive;
|
|
68
60
|
# normalizes also applies to finder values.
|
|
69
61
|
normalizes :coupon_code, with: ->(code) { code.to_s.strip.downcase.presence }
|
|
@@ -87,6 +79,8 @@ module Spree
|
|
|
87
79
|
end
|
|
88
80
|
end
|
|
89
81
|
has_many :fulfillment_items, through: :fulfillments, class_name: 'Spree::FulfillmentItem'
|
|
82
|
+
# Legacy name (5.x carts were orders) — removed in 6.1
|
|
83
|
+
has_many :shipments, -> { order(:created_at, :id) }, class_name: 'Spree::Fulfillment', inverse_of: :cart, deprecated: true
|
|
90
84
|
has_many :order_promotions, class_name: 'Spree::OrderPromotion', inverse_of: :cart, dependent: :destroy
|
|
91
85
|
has_many :promotions, through: :order_promotions, class_name: 'Spree::Promotion'
|
|
92
86
|
has_many :payments, class_name: 'Spree::Payment', inverse_of: :cart, dependent: :destroy
|
|
@@ -167,10 +161,18 @@ module Spree
|
|
|
167
161
|
|
|
168
162
|
# Idempotent delivery-proposal rebuild — replaces the destructive
|
|
169
163
|
# order-side create_proposed_fulfillments. Open fulfillments are rebuilt from
|
|
170
|
-
# the current items/address; nothing here touches a completed cart.
|
|
171
|
-
|
|
164
|
+
# the current items/address; nothing here touches a completed cart. Until
|
|
165
|
+
# deliveries can be proposed the cart gets none: preselecting the pickup
|
|
166
|
+
# rate that is all a destination-less quote finds would choose pickup for
|
|
167
|
+
# a customer who had not been offered anything.
|
|
168
|
+
#
|
|
169
|
+
# @param keep_selection [Boolean] false when the destination changed: a
|
|
170
|
+
# choice made for one address is not a choice for another
|
|
171
|
+
def rebuild_fulfillments!(keep_selection: true)
|
|
172
172
|
return if completed?
|
|
173
173
|
|
|
174
|
+
previous_selections = keep_selection ? fulfillments.selected_rates_by_stock_location : {}
|
|
175
|
+
|
|
174
176
|
discounts.for_fulfillments.delete_all
|
|
175
177
|
tax_lines.for_fulfillments.delete_all
|
|
176
178
|
fees.for_fulfillments.delete_all
|
|
@@ -179,6 +181,7 @@ module Spree
|
|
|
179
181
|
DeliveryRate.where(fulfillment_id: fulfillment_ids).delete_all
|
|
180
182
|
fulfillments.delete_all
|
|
181
183
|
fulfillment_items.reset
|
|
184
|
+
return fulfillments.reload unless can_propose_deliveries?
|
|
182
185
|
|
|
183
186
|
# Appended rather than assigned: setting `cart` on each proposal already
|
|
184
187
|
# files it under this cart's `fulfillments` (the association is
|
|
@@ -188,6 +191,7 @@ module Spree
|
|
|
188
191
|
Spree::Stock::Coordinator.new(self).fulfillments.each do |fulfillment|
|
|
189
192
|
fulfillment.address_id = ship_address_id
|
|
190
193
|
fulfillment.order = nil
|
|
194
|
+
fulfillment.carry_over_selection(previous_selections.fetch(fulfillment.stock_location_id, []))
|
|
191
195
|
fulfillments << fulfillment
|
|
192
196
|
end
|
|
193
197
|
prune_undeliverable_fulfillments!
|
|
@@ -206,7 +210,7 @@ module Spree
|
|
|
206
210
|
self.warnings |= affected_line_items.map do |line_item|
|
|
207
211
|
{
|
|
208
212
|
code: 'delivery_unavailable',
|
|
209
|
-
message:
|
|
213
|
+
message: I18n.t('spree.cart_line_item.delivery_unavailable', li_name: line_item.name),
|
|
210
214
|
line_item_id: line_item.prefixed_id
|
|
211
215
|
}
|
|
212
216
|
end
|
|
@@ -214,7 +218,7 @@ module Spree
|
|
|
214
218
|
|
|
215
219
|
def ensure_available_delivery_rates
|
|
216
220
|
if fulfillments.empty? || fulfillments.any? { |fulfillment| fulfillment.delivery_rates.blank? }
|
|
217
|
-
errors.add(:base, :items_cannot_be_shipped, message:
|
|
221
|
+
errors.add(:base, :items_cannot_be_shipped, message: I18n.t('spree.items_cannot_be_shipped'))
|
|
218
222
|
return false
|
|
219
223
|
end
|
|
220
224
|
true
|
|
@@ -229,7 +233,6 @@ module Spree
|
|
|
229
233
|
updated_at: Time.current
|
|
230
234
|
)
|
|
231
235
|
end
|
|
232
|
-
alias set_shipments_cost set_fulfillments_cost
|
|
233
236
|
|
|
234
237
|
def ensure_updated_fulfillments
|
|
235
238
|
rebuild_fulfillments! unless completed?
|
|
@@ -238,7 +241,11 @@ module Spree
|
|
|
238
241
|
# Re-prices, re-taxes and rebuilds delivery proposals — the
|
|
239
242
|
# recalculation-on-write replacement for transition-triggered rebuilds.
|
|
240
243
|
# Called by Carts::Update after address/market changes.
|
|
241
|
-
|
|
244
|
+
#
|
|
245
|
+
# @param keep_selection [Boolean] true when the parcel still goes where it
|
|
246
|
+
# did (a market change, a corrected phone number), so the chosen
|
|
247
|
+
# delivery is kept and quoted again
|
|
248
|
+
def recalculate_for_address_change!(keep_selection: false)
|
|
242
249
|
# One provider round for the whole cart, and persisted: a per-item loop
|
|
243
250
|
# would ask an external pricing system once per line, and nothing here
|
|
244
251
|
# saves the line items — rebuild_fulfillments! and recalculate_totals!
|
|
@@ -251,8 +258,7 @@ module Spree
|
|
|
251
258
|
raise Spree::Pricing::PriceResolution::ProviderUnavailable, result.error.to_s if result.failure?
|
|
252
259
|
|
|
253
260
|
Spree::Carts::PriceItems.apply(result.value)
|
|
254
|
-
rebuild_fulfillments!
|
|
255
|
-
set_fulfillments_cost
|
|
261
|
+
rebuild_fulfillments!(keep_selection: keep_selection)
|
|
256
262
|
recalculate_totals!
|
|
257
263
|
end
|
|
258
264
|
|
|
@@ -269,11 +275,27 @@ module Spree
|
|
|
269
275
|
reload
|
|
270
276
|
end
|
|
271
277
|
|
|
278
|
+
# The variants this cart's buyer may order: the channel's live
|
|
279
|
+
# publications, narrowed to the catalogs the cart's company, customer
|
|
280
|
+
# group or channel resolve to. Status, stock and currency are left to the
|
|
281
|
+
# add and checkout checks, which explain a refusal rather than reading as
|
|
282
|
+
# not found.
|
|
283
|
+
#
|
|
284
|
+
# @return [ActiveRecord::Relation<Spree::Variant>]
|
|
285
|
+
def orderable_variants
|
|
286
|
+
products = Spree.products_for_context_service.call(
|
|
287
|
+
store: store, channel: channel, customer: customer, company: resolved_company,
|
|
288
|
+
base: store.products.not_discontinued_on(channel)
|
|
289
|
+
).value
|
|
290
|
+
|
|
291
|
+
Spree::Variant.for_products(products)
|
|
292
|
+
end
|
|
293
|
+
|
|
272
294
|
# Removes out-of-stock/discontinued items and populates warnings
|
|
273
295
|
# (mirrors Order#remove_out_of_stock_items!).
|
|
274
296
|
def remove_out_of_stock_items!
|
|
275
297
|
existing_warnings = warnings
|
|
276
|
-
result = Spree
|
|
298
|
+
result = Spree.cart_remove_out_of_stock_items_service.call(cart: self)
|
|
277
299
|
return self unless result.success?
|
|
278
300
|
|
|
279
301
|
cart, _messages, new_warnings = result.value
|
|
@@ -281,5 +303,43 @@ module Spree
|
|
|
281
303
|
cart
|
|
282
304
|
end
|
|
283
305
|
|
|
306
|
+
# Whether this cart shows a batch coupon code it does not hold — used,
|
|
307
|
+
# taken by another cart or order, or given up by one — and so can never
|
|
308
|
+
# discount it.
|
|
309
|
+
#
|
|
310
|
+
# @return [Boolean]
|
|
311
|
+
def coupon_code_unavailable?
|
|
312
|
+
code = read_attribute(:coupon_code)
|
|
313
|
+
return false if code.blank?
|
|
314
|
+
|
|
315
|
+
record = Spree::CouponCode.where(promotion_id: store.promotions.select(:id)).find_by(code: code)
|
|
316
|
+
record.present? && record.cart_id != id
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# Drops an entered batch coupon code this cart no longer holds, and warns
|
|
320
|
+
# the shopper, who otherwise sees the discount vanish.
|
|
321
|
+
#
|
|
322
|
+
# @return [Spree::Cart]
|
|
323
|
+
def remove_unavailable_coupon_code!
|
|
324
|
+
return self unless coupon_code_unavailable?
|
|
325
|
+
|
|
326
|
+
# The lock refuses unsaved attributes and reloads the cart, so this
|
|
327
|
+
# request's warnings are set aside and put back.
|
|
328
|
+
existing_warnings = warnings
|
|
329
|
+
clear_attribute_changes([:warnings])
|
|
330
|
+
removed = with_lock do
|
|
331
|
+
# Checked under the lock, as the completion claim itself is: a
|
|
332
|
+
# completing cart's code sits on its draft order while the payment
|
|
333
|
+
# runs, and a failed payment hands it back.
|
|
334
|
+
next false if completion_claimed? || !coupon_code_unavailable?
|
|
335
|
+
|
|
336
|
+
Spree.coupon_handler.new(self, enable_gift_cards: false).remove(read_attribute(:coupon_code))
|
|
337
|
+
true
|
|
338
|
+
end
|
|
339
|
+
self.warnings = existing_warnings
|
|
340
|
+
self.warnings |= [{ code: 'coupon_code_unavailable', message: I18n.t('spree.coupon_code_unavailable') }] if removed
|
|
341
|
+
self
|
|
342
|
+
end
|
|
343
|
+
|
|
284
344
|
end
|
|
285
345
|
end
|
|
@@ -58,7 +58,7 @@ module Spree
|
|
|
58
58
|
return if STOREFRONT_ACCESS.include?(value.to_s)
|
|
59
59
|
|
|
60
60
|
errors.add(
|
|
61
|
-
:preferred_storefront_access, :invalid_storefront_access, message:
|
|
61
|
+
:preferred_storefront_access, :invalid_storefront_access, message: I18n.t('spree.errors.messages.invalid_storefront_access')
|
|
62
62
|
)
|
|
63
63
|
end
|
|
64
64
|
end
|
data/app/models/spree/channel.rb
CHANGED
|
@@ -14,9 +14,9 @@ module Spree
|
|
|
14
14
|
include Spree::Channel::Gating
|
|
15
15
|
|
|
16
16
|
# Empty -> falls back to the Store-level preference.
|
|
17
|
-
preference :order_routing_strategy, :string, default: nil
|
|
17
|
+
preference :order_routing_strategy, :string, default: nil,
|
|
18
|
+
parse_on_set: ->(value) { Spree::ApiTyped.class_name_for(Spree.order_routing.strategies, value) }
|
|
18
19
|
|
|
19
|
-
belongs_to :store, class_name: 'Spree::Store'
|
|
20
20
|
|
|
21
21
|
has_many :orders, class_name: 'Spree::Order', inverse_of: :channel, dependent: :nullify
|
|
22
22
|
has_many :order_routing_rules, class_name: 'Spree::OrderRoutingRule', dependent: :destroy
|
|
@@ -163,7 +163,7 @@ module Spree
|
|
|
163
163
|
return unless default?
|
|
164
164
|
return if destroyed_by_association.present?
|
|
165
165
|
|
|
166
|
-
errors.add(:base, :cannot_delete_default_channel, message:
|
|
166
|
+
errors.add(:base, :cannot_delete_default_channel, message: I18n.t('spree.errors.messages.cannot_delete_default_channel'))
|
|
167
167
|
throw :abort
|
|
168
168
|
end
|
|
169
169
|
|
|
@@ -176,7 +176,7 @@ module Spree
|
|
|
176
176
|
return unless api_keys.active.exists?
|
|
177
177
|
return if destroyed_by_association.present?
|
|
178
178
|
|
|
179
|
-
errors.add(:base, :cannot_delete_channel_with_active_api_keys, message:
|
|
179
|
+
errors.add(:base, :cannot_delete_channel_with_active_api_keys, message: I18n.t('spree.errors.messages.cannot_delete_channel_with_active_api_keys'))
|
|
180
180
|
throw :abort
|
|
181
181
|
end
|
|
182
182
|
|
data/app/models/spree/claim.rb
CHANGED
|
@@ -16,8 +16,10 @@ module Spree
|
|
|
16
16
|
include Spree::HasStatus
|
|
17
17
|
include Spree::HasCustomFields
|
|
18
18
|
include Spree::Metadata
|
|
19
|
+
include Spree::PostSale::Taxation
|
|
19
20
|
|
|
20
21
|
publishes_lifecycle_events
|
|
22
|
+
publishes_events :approved, :canceled, :denied, :opened, :resolved
|
|
21
23
|
|
|
22
24
|
has_status :open, :approved, :resolved, :denied, :canceled, default: :open
|
|
23
25
|
|
|
@@ -25,7 +27,6 @@ module Spree
|
|
|
25
27
|
# stays closed — an unrecognised value would silently do nothing.
|
|
26
28
|
RESOLUTIONS = %w[refund replacement refund_and_replacement].freeze
|
|
27
29
|
|
|
28
|
-
belongs_to :store, class_name: 'Spree::Store'
|
|
29
30
|
belongs_to :order, class_name: 'Spree::Order', inverse_of: :claims
|
|
30
31
|
belongs_to :reason, class_name: 'Spree::ClaimReason', optional: true, inverse_of: :claims
|
|
31
32
|
acted_by :created_by
|
|
@@ -59,6 +60,21 @@ module Spree
|
|
|
59
60
|
end
|
|
60
61
|
end
|
|
61
62
|
|
|
63
|
+
# The tax inside {#refunded_line_amounts}, for the lines whose tax is
|
|
64
|
+
# recorded: each line's refund carries its tax in proportion to what the
|
|
65
|
+
# customer paid for it.
|
|
66
|
+
#
|
|
67
|
+
# @return [Hash{Integer => BigDecimal}] line item id => tax
|
|
68
|
+
def refunded_line_taxes
|
|
69
|
+
claim_line_items.each_with_object(Hash.new(0)) do |line, taxes|
|
|
70
|
+
next unless line.settles_tax? && line.paid_amount.positive?
|
|
71
|
+
|
|
72
|
+
taxes[line.line_item_id] += Spree::Money::Rounding.to_currency(
|
|
73
|
+
line.tax_total * line.refund_amount.to_d / line.paid_amount, currency
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
62
78
|
def display_refund_total
|
|
63
79
|
Spree::Money.new(refund_total, currency: currency)
|
|
64
80
|
end
|
|
@@ -66,5 +82,9 @@ module Spree
|
|
|
66
82
|
def replacement_line_items
|
|
67
83
|
claim_line_items.select(&:send_replacement)
|
|
68
84
|
end
|
|
85
|
+
|
|
86
|
+
def taxed_lines
|
|
87
|
+
claim_line_items
|
|
88
|
+
end
|
|
69
89
|
end
|
|
70
90
|
end
|