spree_core 6.0.0.beta4 → 6.0.0.rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -5
- data/app/helpers/spree/images_helper.rb +0 -57
- data/app/jobs/spree/base_job.rb +21 -0
- data/app/jobs/spree/carts/reap_expired_job.rb +2 -2
- data/app/jobs/spree/collections/regenerate_time_based_job.rb +6 -3
- data/app/jobs/spree/orders/finalize_stale_drafts_job.rb +8 -5
- data/app/jobs/spree/payments/cancel_unused_sessions_job.rb +61 -0
- data/app/jobs/spree/search_provider/index_job.rb +4 -0
- data/app/jobs/spree/seller_payouts/sweep_seller_job.rb +2 -0
- data/app/jobs/spree/uploads/purge_unattached_job.rb +49 -0
- data/app/mailers/spree/admin_user_mailer.rb +4 -19
- data/app/mailers/spree/base_mailer.rb +97 -13
- data/app/mailers/spree/email_template_mailer.rb +27 -0
- data/app/mailers/spree/export_mailer.rb +3 -4
- data/app/mailers/spree/import_mailer.rb +3 -4
- data/app/mailers/spree/invitation_mailer.rb +24 -7
- data/app/mailers/spree/seller_user_mailer.rb +4 -16
- data/app/mailers/spree/webhook_mailer.rb +2 -2
- data/app/models/concerns/spree/acted_by.rb +1 -1
- data/app/models/concerns/spree/admin_user_methods.rb +15 -1
- data/app/models/concerns/spree/api_typed.rb +91 -0
- data/app/models/concerns/spree/calculated_adjustments.rb +41 -13
- data/app/models/concerns/spree/calculator/currency_amounts.rb +1 -1
- data/app/models/concerns/spree/calculator/tiers.rb +63 -0
- data/app/models/concerns/spree/canonical_decimals.rb +61 -0
- data/app/models/concerns/spree/customer_methods.rb +23 -18
- data/app/models/concerns/spree/derived_number.rb +11 -13
- data/app/models/concerns/spree/email_template_identity.rb +52 -0
- data/app/models/concerns/spree/parameterizable_name.rb +2 -0
- data/app/models/concerns/spree/payment_session_transitions.rb +8 -2
- data/app/models/concerns/spree/post_sale/taxation.rb +54 -0
- data/app/models/concerns/spree/post_sale/taxed_line.rb +51 -0
- data/app/models/concerns/spree/preference_schema/json_schema.rb +139 -0
- data/app/models/concerns/spree/preference_schema.rb +62 -32
- data/app/models/concerns/spree/product_scopes.rb +16 -2
- data/app/models/concerns/spree/provider_listing.rb +41 -0
- data/app/models/concerns/spree/publishable.rb +82 -14
- data/app/models/concerns/spree/purchase/addresses.rb +23 -10
- data/app/models/concerns/spree/purchase/currency.rb +1 -1
- data/app/models/concerns/spree/purchase/deprecated_aliases.rb +87 -0
- data/app/models/concerns/spree/purchase/gift_cards.rb +10 -4
- data/app/models/concerns/spree/purchase/locale.rb +1 -1
- data/app/models/concerns/spree/purchase/payment_processing.rb +8 -4
- data/app/models/concerns/spree/purchase/purchase_order.rb +9 -4
- data/app/models/concerns/spree/purchase/store_credits.rb +36 -1
- data/app/models/concerns/spree/purchase/totals.rb +49 -8
- data/app/models/concerns/spree/ransackable_attributes.rb +46 -0
- data/app/models/concerns/spree/receivable.rb +1 -1
- data/app/models/concerns/spree/searchable.rb +0 -4
- data/app/models/concerns/spree/secret_preferences.rb +59 -0
- data/app/models/concerns/spree/signed_id_attachments.rb +54 -0
- data/app/models/concerns/spree/single_store_resource.rb +1 -1
- data/app/models/concerns/spree/stores/email_branding.rb +32 -0
- data/app/models/concerns/spree/stores/markets.rb +5 -2
- data/app/models/concerns/spree/type_labels.rb +38 -0
- data/app/models/concerns/spree/typed_adjustment_line.rb +5 -6
- data/app/models/concerns/spree/typed_associations.rb +12 -18
- data/app/models/concerns/spree/vat_price_calculation.rb +5 -6
- data/app/models/spree/address.rb +12 -2
- data/app/models/spree/adjusters/largest_remainder.rb +14 -1
- data/app/models/spree/adjusters/promotion.rb +4 -19
- data/app/models/spree/allowed_origin.rb +3 -1
- data/app/models/spree/api_key.rb +5 -6
- data/app/models/spree/authentication/strategies/oidc_strategy.rb +5 -5
- data/app/models/spree/base.rb +99 -22
- data/app/models/spree/calculator/flat_percent_item_total.rb +2 -4
- data/app/models/spree/calculator/flat_rate.rb +3 -5
- data/app/models/spree/calculator/flexi_rate.rb +4 -6
- data/app/models/spree/calculator/percent_on_line_item.rb +2 -2
- data/app/models/spree/calculator/price_sack.rb +5 -7
- data/app/models/spree/calculator/shipping/digital_delivery.rb +3 -5
- data/app/models/spree/calculator/shipping/flat_percent_item_total.rb +7 -7
- data/app/models/spree/calculator/shipping/flat_rate.rb +5 -7
- data/app/models/spree/calculator/shipping/flexi_rate.rb +4 -6
- data/app/models/spree/calculator/shipping/per_item.rb +3 -5
- data/app/models/spree/calculator/shipping/price_sack.rb +5 -7
- data/app/models/spree/calculator/tiered_flat_rate.rb +7 -24
- data/app/models/spree/calculator/tiered_percent.rb +7 -25
- data/app/models/spree/cart.rb +78 -18
- data/app/models/spree/catalog.rb +1 -0
- data/app/models/spree/catalog_price.rb +0 -7
- data/app/models/spree/catalog_price_tier.rb +0 -8
- data/app/models/spree/category.rb +3 -1
- data/app/models/spree/channel/gating.rb +3 -2
- data/app/models/spree/channel.rb +6 -4
- data/app/models/spree/claim.rb +22 -1
- data/app/models/spree/claim_line_item.rb +41 -6
- data/app/models/spree/collection.rb +2 -1
- data/app/models/spree/collection_rule.rb +5 -21
- data/app/models/spree/commission_line.rb +1 -1
- data/app/models/spree/commission_rate.rb +7 -4
- data/app/models/spree/commission_rate_value.rb +1 -1
- data/app/models/spree/commission_rule.rb +4 -11
- data/app/models/spree/commission_rules/category_rule.rb +2 -5
- data/app/models/spree/commission_rules/item_total_rule.rb +2 -2
- data/app/models/spree/commission_rules/product_rule.rb +1 -1
- data/app/models/spree/commission_rules/seller_rule.rb +2 -5
- data/app/models/spree/company.rb +1 -0
- data/app/models/spree/company_invitation.rb +1 -0
- data/app/models/spree/consent_record.rb +0 -1
- data/app/models/spree/credit_card.rb +1 -1
- data/app/models/spree/current.rb +23 -0
- data/app/models/spree/custom_field.rb +2 -2
- data/app/models/spree/custom_field_definition.rb +20 -35
- data/app/models/spree/custom_fields/boolean.rb +1 -1
- data/app/models/spree/custom_fields/json.rb +1 -1
- data/app/models/spree/customer_group.rb +1 -0
- data/app/models/spree/data_feed/google.rb +0 -2
- data/app/models/spree/data_request.rb +2 -1
- data/app/models/spree/delivery_method.rb +36 -14
- data/app/models/spree/delivery_method_rule.rb +4 -11
- data/app/models/spree/delivery_method_rules/channel_rule.rb +2 -5
- data/app/models/spree/delivery_method_rules/item_total_rule.rb +2 -2
- data/app/models/spree/delivery_profile.rb +1 -0
- data/app/models/spree/delivery_rate.rb +7 -8
- data/app/models/spree/delivery_rate_provider/base.rb +1 -0
- data/app/models/spree/delivery_zone.rb +1 -2
- data/app/models/spree/delivery_zone_member.rb +4 -4
- data/app/models/spree/digital_asset.rb +7 -0
- data/app/models/spree/digital_asset_provider/base.rb +2 -0
- data/app/models/spree/digital_link.rb +2 -5
- data/app/models/spree/discount.rb +1 -1
- data/app/models/spree/email_template.rb +25 -0
- data/app/models/spree/email_template_draft.rb +13 -0
- data/app/models/spree/email_template_revision.rb +17 -0
- data/app/models/spree/email_templates/entry.rb +118 -0
- data/app/models/spree/email_templates/sample_record.rb +16 -0
- data/app/models/spree/emails/branding.rb +80 -0
- data/app/models/spree/exchange.rb +16 -1
- data/app/models/spree/exchange_line_item.rb +121 -5
- data/app/models/spree/export.rb +0 -1
- data/app/models/spree/exports/products.rb +10 -1
- data/app/models/spree/exports/report.rb +3 -3
- data/app/models/spree/fee.rb +4 -2
- data/app/models/spree/file_upload.rb +155 -0
- data/app/models/spree/fulfillment.rb +66 -30
- data/app/models/spree/fulfillment_changer.rb +2 -2
- data/app/models/spree/fulfillment_group.rb +6 -1
- data/app/models/spree/fulfillment_item.rb +0 -4
- data/app/models/spree/fulfillment_provider/base.rb +1 -0
- data/app/models/spree/gateway/bogus.rb +6 -0
- data/app/models/spree/gateway/custom_payment_source_method.rb +5 -0
- data/app/models/spree/gateway.rb +6 -2
- data/app/models/spree/gift_card.rb +18 -8
- data/app/models/spree/gift_card_batch.rb +3 -5
- data/app/models/spree/import.rb +5 -7
- data/app/models/spree/import_mapping.rb +1 -2
- data/app/models/spree/import_row.rb +2 -2
- data/app/models/spree/import_schemas/products.rb +1 -0
- data/app/models/spree/integration.rb +9 -19
- data/app/models/spree/invitation.rb +5 -5
- data/app/models/spree/line_item.rb +15 -4
- data/app/models/spree/locale.rb +11 -8
- data/app/models/spree/market.rb +8 -2
- data/app/models/spree/media.rb +1 -9
- data/app/models/spree/newsletter_subscriber.rb +4 -0
- data/app/models/spree/option_type.rb +2 -1
- data/app/models/spree/option_value.rb +2 -1
- data/app/models/spree/order.rb +60 -142
- data/app/models/spree/order_group.rb +18 -4
- data/app/models/spree/order_inventory.rb +10 -5
- data/app/models/spree/order_promotion.rb +1 -1
- data/app/models/spree/order_routing/has_strategy_preference.rb +1 -1
- data/app/models/spree/order_routing/strategy/base.rb +4 -2
- data/app/models/spree/order_routing/strategy/rules.rb +1 -1
- data/app/models/spree/order_routing_rule.rb +6 -22
- data/app/models/spree/package_type.rb +2 -2
- data/app/models/spree/payment/gateway_options.rb +15 -53
- data/app/models/spree/payment/processing.rb +2 -4
- data/app/models/spree/payment.rb +21 -13
- data/app/models/spree/payment_method/check.rb +2 -0
- data/app/models/spree/payment_method/session_instrumentation.rb +1 -0
- data/app/models/spree/payment_method/store_credit.rb +15 -13
- data/app/models/spree/payment_method.rb +78 -6
- data/app/models/spree/payment_session.rb +5 -1
- data/app/models/spree/payment_setup_session.rb +1 -0
- data/app/models/spree/payout_provider/base.rb +3 -1
- data/app/models/spree/pickup_point_provider/base.rb +2 -0
- data/app/models/spree/policy.rb +1 -0
- data/app/models/spree/price.rb +17 -14
- data/app/models/spree/price_adjustment_tier.rb +4 -0
- data/app/models/spree/price_list.rb +14 -9
- data/app/models/spree/price_rules/channel_rule.rb +3 -6
- data/app/models/spree/price_rules/customer_group_rule.rb +3 -6
- data/app/models/spree/price_rules/market_rule.rb +2 -5
- data/app/models/spree/price_rules/user_rule.rb +1 -3
- data/app/models/spree/product/channels.rb +9 -2
- data/app/models/spree/product.rb +54 -30
- data/app/models/spree/product_submission.rb +0 -12
- data/app/models/spree/product_type.rb +1 -1
- data/app/models/spree/promotion/actions/create_line_items.rb +28 -18
- data/app/models/spree/promotion/rules/category.rb +1 -5
- data/app/models/spree/promotion/rules/channel.rb +2 -9
- data/app/models/spree/promotion/rules/country.rb +3 -8
- data/app/models/spree/promotion/rules/currency.rb +1 -5
- data/app/models/spree/promotion/rules/customer_group.rb +2 -9
- data/app/models/spree/promotion/rules/first_order.rb +0 -4
- data/app/models/spree/promotion/rules/item_total.rb +6 -10
- data/app/models/spree/promotion/rules/market.rb +2 -9
- data/app/models/spree/promotion/rules/one_use_per_user.rb +0 -4
- data/app/models/spree/promotion/rules/option_value.rb +2 -6
- data/app/models/spree/promotion/rules/product.rb +1 -5
- data/app/models/spree/promotion/rules/user.rb +0 -4
- data/app/models/spree/promotion/rules/user_logged_in.rb +0 -4
- data/app/models/spree/promotion.rb +36 -6
- data/app/models/spree/promotion_action.rb +7 -14
- data/app/models/spree/promotion_action_line_item.rb +1 -1
- data/app/models/spree/promotion_handler/coupon.rb +59 -27
- data/app/models/spree/promotion_rule.rb +7 -14
- data/app/models/spree/purchase_order.rb +3 -0
- data/app/models/spree/quantity_rule.rb +1 -1
- data/app/models/spree/refund.rb +41 -18
- data/app/models/spree/return.rb +31 -2
- data/app/models/spree/return_line_item.rb +65 -14
- data/app/models/spree/role.rb +7 -7
- data/app/models/spree/saved_report.rb +2 -1
- data/app/models/spree/search_provider/base.rb +4 -0
- data/app/models/spree/seller.rb +10 -2
- data/app/models/spree/seller_payout.rb +8 -0
- data/app/models/spree/seller_requirement.rb +5 -12
- data/app/models/spree/seller_requirement_custom_field.rb +1 -2
- data/app/models/spree/seller_requirement_submission.rb +3 -2
- data/app/models/spree/seller_requirements/accept_terms.rb +2 -3
- data/app/models/spree/seller_transfer.rb +6 -0
- data/app/models/spree/shipping_label.rb +2 -0
- data/app/models/spree/stock/availability_validator.rb +2 -2
- data/app/models/spree/stock/estimator.rb +1 -1
- data/app/models/spree/stock/inventory_unit_builder.rb +1 -1
- data/app/models/spree/stock/packer.rb +2 -2
- data/app/models/spree/stock/splitter/weight.rb +1 -1
- data/app/models/spree/stock_level/custom_events.rb +6 -0
- data/app/models/spree/stock_level.rb +3 -1
- data/app/models/spree/stock_location.rb +1 -0
- data/app/models/spree/stock_movement.rb +1 -1
- data/app/models/spree/stock_receipt_item.rb +1 -1
- data/app/models/spree/stock_reservation.rb +2 -2
- data/app/models/spree/stock_transfer.rb +6 -2
- data/app/models/spree/store.rb +70 -19
- data/app/models/spree/store_credit.rb +13 -13
- data/app/models/spree/store_credit_event.rb +5 -5
- data/app/models/spree/supplier.rb +1 -0
- data/app/models/spree/tax_category.rb +1 -0
- data/app/models/spree/tax_exemption_certificate.rb +3 -0
- data/app/models/spree/tax_identifier.rb +3 -1
- data/app/models/spree/tax_line.rb +53 -3
- data/app/models/spree/tax_provider/base.rb +71 -14
- data/app/models/spree/tax_provider/internal.rb +70 -41
- data/app/models/spree/tax_provider/recorded_share.rb +114 -0
- data/app/models/spree/tax_rate.rb +30 -8
- data/app/models/spree/taxon.rb +1 -1
- data/app/models/spree/taxonomy.rb +0 -1
- data/app/models/spree/update_status.rb +25 -0
- data/app/models/spree/variant.rb +10 -12
- data/app/models/spree/variant_media.rb +1 -1
- data/app/models/spree/webhook_delivery.rb +1 -0
- data/app/models/spree/webhook_endpoint.rb +46 -13
- data/app/models/spree/wishlist.rb +1 -6
- data/app/models/spree/wishlist_item/custom_events.rb +6 -0
- data/app/presenters/spree/csv/customer_presenter.rb +1 -1
- data/app/presenters/spree/csv/newsletter_subscriber_presenter.rb +1 -1
- data/app/presenters/spree/csv/order_line_item_presenter.rb +10 -6
- data/app/presenters/spree/csv/price_list_price_presenter.rb +3 -8
- data/app/presenters/spree/csv/product_variant_presenter.rb +59 -20
- data/app/presenters/spree/csv/purchase_order_item_presenter.rb +1 -3
- data/app/serializers/spree/emails/base_serializer.rb +14 -0
- data/app/serializers/spree/emails/export_serializer.rb +13 -0
- data/app/serializers/spree/emails/import_serializer.rb +19 -0
- data/app/serializers/spree/emails/invitation_serializer.rb +28 -0
- data/app/serializers/spree/emails/store_serializer.rb +31 -0
- data/app/serializers/spree/emails/user_serializer.rb +12 -0
- data/app/serializers/spree/emails/webhook_endpoint_serializer.rb +16 -0
- data/app/services/spree/carts/create.rb +8 -2
- data/app/services/spree/carts/destroy.rb +2 -2
- data/app/services/spree/carts/remove_out_of_stock_items.rb +2 -2
- data/app/services/spree/carts/split_by_seller.rb +1 -1
- data/app/services/spree/carts/update.rb +22 -8
- data/app/services/spree/catalogs/set_product_terms.rb +1 -1
- data/app/services/spree/categories/add_products.rb +13 -31
- data/app/services/spree/categories/remove_products.rb +12 -51
- data/app/services/spree/checkout/advance.rb +1 -4
- data/app/services/spree/collections/add_products.rb +10 -23
- data/app/services/spree/collections/remove_products.rb +7 -43
- data/app/services/spree/coupon_codes/bulk_generate.rb +8 -14
- data/app/services/spree/data_requests/create.rb +1 -1
- data/app/services/spree/deliveries/destroy.rb +2 -2
- data/app/services/spree/email_templates/check.rb +58 -0
- data/app/services/spree/email_templates/no_sample_record.rb +7 -0
- data/app/services/spree/email_templates/preview.rb +99 -0
- data/app/services/spree/emails/file_system.rb +23 -0
- data/app/services/spree/emails/filters.rb +84 -0
- data/app/services/spree/emails/liquid_context.rb +48 -0
- data/app/services/spree/emails/rendered_email.rb +14 -0
- data/app/services/spree/emails/renderer.rb +125 -0
- data/app/services/spree/emails/template.rb +51 -0
- data/app/services/spree/emails/template_data.rb +23 -0
- data/app/services/spree/emails/template_resolver.rb +109 -0
- data/app/services/spree/emails/text_converter.rb +72 -0
- data/app/services/spree/emails/translation_inliner.rb +134 -0
- data/app/services/spree/imports/row_processors/price_list_price.rb +10 -10
- data/app/services/spree/imports/row_processors/product_variant.rb +77 -34
- data/app/services/spree/imports/row_processors/purchase_order.rb +13 -13
- data/app/services/spree/locales.rb +43 -10
- data/app/services/spree/newsletter/subscribe.rb +8 -12
- data/app/services/spree/orders/build_fulfillments.rb +3 -2
- data/app/services/spree/orders/create.rb +5 -4
- data/app/services/spree/orders/discounts/create.rb +14 -11
- data/app/services/spree/orders/discounts/destroy.rb +1 -0
- data/app/services/spree/orders/discounts/update.rb +1 -0
- data/app/services/spree/orders/fees/create.rb +1 -0
- data/app/services/spree/orders/fees/destroy.rb +1 -0
- data/app/services/spree/orders/fees/update.rb +1 -0
- data/app/services/spree/orders/remove_line_item.rb +13 -3
- data/app/services/spree/orders/update.rb +10 -6
- data/app/services/spree/orders/update_item.rb +6 -3
- data/app/services/spree/orders/update_statuses.rb +3 -1
- data/app/services/spree/prices/bulk_upsert.rb +32 -25
- data/app/services/spree/product_memberships.rb +61 -0
- data/app/services/spree/returns/eligibility_validator.rb +1 -1
- data/app/services/spree/search_provider/custom_field_schema.rb +2 -2
- data/app/services/spree/seeds/commission_rates.rb +1 -1
- data/app/services/spree/seeds/digital_delivery.rb +1 -1
- data/app/services/spree/seeds/payment_methods.rb +2 -2
- data/app/services/spree/seeds/saved_reports.rb +3 -3
- data/app/services/spree/seeds/stores.rb +1 -1
- data/app/services/spree/sellers/requirements.rb +1 -2
- data/app/services/spree/shipping_labels/confirm_refund.rb +1 -1
- data/app/services/spree/shipping_labels/store_file.rb +3 -3
- data/app/services/spree/stock_levels/correct.rb +3 -3
- data/app/services/spree/stock_reservations/reserve.rb +2 -3
- data/app/services/spree/store_credits/apply.rb +15 -13
- data/app/services/spree/stores/provision_defaults.rb +23 -25
- data/app/services/spree/update_check.rb +160 -0
- data/app/services/spree/uploads/assign_stores.rb +92 -0
- data/app/subscribers/spree/seller_onboarding_subscriber.rb +1 -1
- data/app/validators/spree/attachment_content_type_validator.rb +19 -2
- data/app/validators/spree/locale_codes_validator.rb +22 -0
- data/app/views/layouts/spree/base_mailer.html.erb +2 -43
- data/app/views/layouts/spree/base_mailer.liquid +79 -0
- data/app/views/spree/admin_user_mailer/password_reset_email.liquid +14 -0
- data/app/views/spree/export_mailer/export_done.liquid +12 -0
- data/app/views/spree/import_mailer/import_done.liquid +15 -0
- data/app/views/spree/invitation_mailer/invitation_accepted.liquid +9 -0
- data/app/views/spree/invitation_mailer/invitation_email.liquid +13 -0
- data/app/views/spree/seller_user_mailer/password_reset_email.liquid +14 -0
- data/app/views/spree/shared/_mailer_button.html.erb +4 -5
- data/app/views/spree/shared/_mailer_hero.html.erb +6 -5
- data/app/views/spree/shared/_summary_row.liquid +8 -0
- data/app/views/spree/webhook_mailer/endpoint_disabled.liquid +21 -0
- data/app/workflows/spree/carts/add_item.rb +4 -4
- data/app/workflows/spree/carts/complete.rb +13 -3
- data/app/workflows/spree/carts/merge.rb +1 -1
- data/app/workflows/spree/carts/recalculate_totals.rb +5 -0
- data/app/workflows/spree/carts/upsert_items.rb +18 -9
- data/app/workflows/spree/claims/approve.rb +5 -22
- data/app/workflows/spree/claims/cancel.rb +5 -21
- data/app/workflows/spree/claims/create.rb +15 -0
- data/app/workflows/spree/claims/deny.rb +7 -0
- data/app/workflows/spree/claims/resolve.rb +34 -31
- data/app/workflows/spree/customers/anonymize.rb +3 -4
- data/app/workflows/spree/customers/create.rb +1 -1
- data/app/workflows/spree/data_requests/fulfill.rb +2 -2
- data/app/workflows/spree/deliveries/update_tracking.rb +1 -1
- data/app/workflows/spree/email_templates/discard_draft.rb +20 -0
- data/app/workflows/spree/email_templates/publish.rb +70 -0
- data/app/workflows/spree/email_templates/restore_revision.rb +33 -0
- data/app/workflows/spree/email_templates/revert.rb +29 -0
- data/app/workflows/spree/email_templates/save_draft.rb +85 -0
- data/app/workflows/spree/exchanges/approve.rb +5 -22
- data/app/workflows/spree/exchanges/cancel.rb +5 -21
- data/app/workflows/spree/exchanges/create.rb +6 -0
- data/app/workflows/spree/exchanges/fulfill.rb +75 -51
- data/app/workflows/spree/exchanges/receive.rb +6 -65
- data/app/workflows/spree/fulfillments/cancel.rb +1 -1
- data/app/workflows/spree/fulfillments/create.rb +53 -49
- data/app/workflows/spree/fulfillments/fulfill.rb +23 -27
- data/app/workflows/spree/fulfillments/mark_delivered.rb +1 -1
- data/app/workflows/spree/fulfillments/replacements.rb +59 -0
- data/app/workflows/spree/gift_cards/apply.rb +2 -2
- data/app/workflows/spree/orders/add_item.rb +5 -1
- data/app/workflows/spree/orders/cancel.rb +3 -3
- data/app/workflows/spree/orders/complete.rb +16 -8
- data/app/workflows/spree/payments/capture.rb +20 -5
- data/app/workflows/spree/payments/process.rb +5 -3
- data/app/workflows/spree/post_sale/approval.rb +35 -0
- data/app/workflows/spree/post_sale/cancellation.rb +44 -0
- data/app/workflows/spree/post_sale/receipt.rb +92 -0
- data/app/workflows/spree/price_lists/update.rb +4 -4
- data/app/workflows/spree/products/nested_attributes.rb +1 -1
- data/app/workflows/spree/purchase_orders/cancel.rb +1 -1
- data/app/workflows/spree/purchase_orders/close.rb +3 -31
- data/app/workflows/spree/purchase_orders/create.rb +3 -1
- data/app/workflows/spree/purchase_orders/mark_draft.rb +2 -2
- data/app/workflows/spree/purchase_orders/mark_ordered.rb +2 -2
- data/app/workflows/spree/purchase_orders/receive.rb +1 -1
- data/app/workflows/spree/purchase_orders/update.rb +5 -34
- data/app/workflows/spree/receivables/closing_short.rb +46 -0
- data/app/workflows/spree/receivables/draft_editing.rb +48 -0
- data/app/workflows/spree/refunds/create.rb +5 -2
- data/app/workflows/spree/refunds/order_payments.rb +14 -2
- data/app/workflows/spree/refunds/tax_credit.rb +67 -0
- data/app/workflows/spree/returns/approve.rb +5 -22
- data/app/workflows/spree/returns/cancel.rb +5 -22
- data/app/workflows/spree/returns/create.rb +8 -0
- data/app/workflows/spree/returns/receive.rb +5 -76
- data/app/workflows/spree/returns/refund.rb +31 -8
- data/app/workflows/spree/seller_requirement_submissions/create.rb +1 -2
- data/app/workflows/spree/seller_transfers/reverse.rb +28 -1
- data/app/workflows/spree/shipping_labels/purchase.rb +8 -8
- data/app/workflows/spree/shipping_labels/record.rb +7 -7
- data/app/workflows/spree/shipping_labels/refund.rb +2 -2
- data/app/workflows/spree/stock_receipts/recording.rb +4 -4
- data/app/workflows/spree/stock_transfers/cancel.rb +2 -2
- data/app/workflows/spree/stock_transfers/close.rb +3 -30
- data/app/workflows/spree/stock_transfers/create.rb +3 -1
- data/app/workflows/spree/stock_transfers/mark_draft.rb +1 -1
- data/app/workflows/spree/stock_transfers/mark_in_transit.rb +3 -3
- data/app/workflows/spree/stock_transfers/mark_ready.rb +2 -2
- data/app/workflows/spree/stock_transfers/receive.rb +1 -1
- data/app/workflows/spree/stock_transfers/update.rb +5 -33
- data/config/currency_exponents.json +180 -0
- data/config/i18n-tasks.yml +32 -18
- data/config/initializers/alba.rb +7 -0
- data/config/language_names.csv +264 -0
- data/config/locales/ar.yml +811 -0
- data/config/locales/be.yml +855 -0
- data/config/locales/bg.yml +723 -0
- data/config/locales/ca.yml +689 -0
- data/config/locales/content_locales.rb +9 -0
- data/config/locales/cs.yml +855 -0
- data/config/locales/da.yml +771 -0
- data/config/locales/de-CH.yml +248 -0
- data/config/locales/de.yml +835 -0
- data/config/locales/el.yml +769 -0
- data/config/locales/en.yml +47 -505
- data/config/locales/es-CL.yml +301 -0
- data/config/locales/es-EC.yml +186 -0
- data/config/locales/es-MX.yml +334 -0
- data/config/locales/es.yml +831 -0
- data/config/locales/et.yml +644 -0
- data/config/locales/fa.yml +709 -0
- data/config/locales/fi.yml +771 -0
- data/config/locales/fr.yml +830 -0
- data/config/locales/hu.yml +751 -0
- data/config/locales/id.yml +756 -0
- data/config/locales/it.yml +833 -0
- data/config/locales/ja.yml +726 -0
- data/config/locales/km.yml +759 -0
- data/config/locales/ko.yml +575 -0
- data/config/locales/ku.yml +753 -0
- data/config/locales/lt.yml +821 -0
- data/config/locales/lv.yml +685 -0
- data/config/locales/nb.yml +824 -0
- data/config/locales/ne.yml +823 -0
- data/config/locales/nl.yml +826 -0
- data/config/locales/pl.yml +835 -0
- data/config/locales/pt-BR.yml +547 -0
- data/config/locales/pt.yml +636 -0
- data/config/locales/ro.yml +750 -0
- data/config/locales/ru.yml +834 -0
- data/config/locales/sk.yml +680 -0
- data/config/locales/sl-SI.yml +600 -0
- data/config/locales/sv.yml +827 -0
- data/config/locales/th.yml +745 -0
- data/config/locales/tr.yml +777 -0
- data/config/locales/uk.yml +836 -0
- data/config/locales/vi.yml +768 -0
- data/config/locales/zh-CN.yml +786 -0
- data/config/locales/zh-TW.yml +834 -0
- data/db/migrate/20260925000001_add_replacement_to_spree_fulfillment_items.rb +5 -0
- data/db/migrate/20261001000001_add_post_sale_tax.rb +30 -0
- data/db/migrate/20261001000001_convert_preferences_to_json.rb +166 -0
- data/db/migrate/20261001000001_create_spree_email_templates.rb +52 -0
- data/db/migrate/20261009000001_change_money_columns_to_decimal_19_4.rb +116 -0
- data/db/migrate/20261010000001_add_store_id_to_active_storage_blobs.rb +12 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +0 -9
- data/lib/generators/spree/dummy/templates/rails/test.rb +26 -0
- data/lib/spree/checkout/default_requirements.rb +37 -13
- data/lib/spree/core/configuration.rb +19 -1
- data/lib/spree/core/controller_helpers/store.rb +1 -1
- data/lib/spree/core/dependencies.rb +5 -4
- data/lib/spree/core/emails/escaped_output.rb +60 -0
- data/lib/spree/core/engine.rb +72 -165
- data/lib/spree/core/permissions/default_catalog.rb +5 -0
- data/lib/spree/core/preferences/invalid_preferences.rb +18 -0
- data/lib/spree/core/preferences/json_conversion.rb +186 -0
- data/lib/spree/core/preferences/masking.rb +55 -2
- data/lib/spree/core/preferences/preferable.rb +343 -103
- data/lib/spree/core/preferences/preferable_class_methods.rb +188 -136
- data/lib/spree/core/previews/import_preview.rb +10 -0
- data/lib/spree/core/ransack_configuration.rb +13 -2
- data/lib/spree/core/tax/provider_error.rb +37 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +91 -373
- data/lib/spree/emails/editable_templates.rb +82 -0
- data/lib/spree/events/catalog.rb +189 -0
- data/lib/spree/events.rb +21 -1
- data/lib/spree/hooks.rb +0 -17
- data/lib/spree/i18n.rb +32 -15
- data/lib/spree/iso_data.rb +7 -0
- data/lib/spree/localized_number.rb +6 -0
- data/lib/spree/migrations.rb +4 -1
- data/lib/spree/money.rb +196 -15
- data/lib/spree/reporting/adapters/base.rb +7 -6
- data/lib/spree/reporting/adapters/live.rb +6 -6
- data/lib/spree/reporting/default_vocabulary.rb +22 -10
- data/lib/spree/reporting/hydration.rb +1 -1
- data/lib/spree/reporting/query.rb +8 -0
- data/lib/spree/reporting/registry.rb +13 -0
- data/lib/spree/reporting/schema.rb +10 -10
- data/lib/spree/testing_support/editable_email_templates.rb +61 -0
- data/lib/spree/testing_support/emails.rb +22 -0
- data/lib/spree/testing_support/factories/cart_factory.rb +1 -1
- data/lib/spree/testing_support/factories/email_template_factory.rb +28 -0
- data/lib/spree/testing_support/factories/order_factory.rb +2 -2
- data/lib/spree/testing_support/factories/product_factory.rb +9 -0
- data/lib/spree/testing_support/factories/refund_factory.rb +1 -1
- data/lib/spree/testing_support/factories/stock_factory.rb +1 -1
- data/lib/spree/testing_support/factories/variant_factory.rb +1 -1
- data/lib/spree/testing_support/i18n.rb +3 -94
- data/lib/spree/testing_support/lifecycle_events.rb +1 -1
- data/lib/spree/testing_support/order_walkthrough.rb +1 -1
- data/lib/spree/testing_support/preferences.rb +0 -5
- data/lib/spree/testing_support/store.rb +9 -1
- data/lib/spree/upgrades/5_6_to_6_0/manifest.yml +67 -1
- data/lib/spree/uploads.rb +101 -0
- data/lib/tasks/categories_and_collections.rake +3 -3
- data/lib/tasks/core.rake +6 -4
- data/lib/tasks/markets.rake +2 -1
- data/lib/tasks/media.rake +3 -3
- data/lib/tasks/migrate_users_to_customers.rake +23 -18
- data/lib/tasks/money.rake +46 -0
- data/lib/tasks/package_types.rake +1 -1
- data/lib/tasks/preferences_json.rake +101 -0
- data/lib/tasks/seller_sample_data.rake +2 -2
- data/lib/tasks/store_settings.rake +13 -6
- data/lib/tasks/typed_adjustments_migration.rake +1 -1
- data/lib/tasks/uploads.rake +19 -0
- data/spec/fixtures/mailer_views/custom_views_probe_mailer/welcome_email.html.erb +4 -0
- metadata +219 -46
- data/app/jobs/spree/products/touch_categories_job.rb +0 -15
- data/app/jobs/spree/products/touch_taxons_job.rb +0 -13
- data/app/models/acts_as_taggable_on/tag_decorator.rb +0 -10
- data/app/models/concerns/spree/has_image_alt_text.rb +0 -18
- data/app/models/spree/base_analytics_event_handler.rb +0 -54
- data/app/models/spree/invitations/store.rb +0 -6
- data/app/models/spree/preference.rb +0 -14
- data/app/models/spree/promotion_handler/page.rb +0 -25
- data/app/models/spree/promotion_handler/promotion_duplicator.rb +0 -60
- data/app/models/spree/stock/differentiator.rb +0 -45
- data/app/presenters/spree/filters/options_presenter.rb +0 -47
- data/app/services/spree/carts/empty.rb +0 -42
- data/app/services/spree/country_to_timezone.rb +0 -273
- data/app/services/spree/payments/create.rb +0 -92
- data/app/validators/spree/url_validator.rb +0 -23
- data/app/views/active_storage/blobs/_blob.html.erb +0 -14
- data/app/views/spree/admin_user_mailer/password_reset_email.html.erb +0 -8
- data/app/views/spree/export_mailer/export_done.html.erb +0 -7
- data/app/views/spree/import_mailer/import_done.html.erb +0 -12
- data/app/views/spree/invitation_mailer/invitation_accepted.html.erb +0 -4
- data/app/views/spree/invitation_mailer/invitation_email.html.erb +0 -12
- data/app/views/spree/seller_user_mailer/password_reset_email.html.erb +0 -8
- data/app/views/spree/shared/_base_mailer_footer.html.erb +0 -19
- data/app/views/spree/shared/_base_mailer_header.html.erb +0 -8
- data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +0 -399
- data/app/views/spree/shared/_mailer_logo.html.erb +0 -41
- data/app/views/spree/shared/_purchased_items_styles.html.erb +0 -119
- data/app/views/spree/webhook_mailer/endpoint_disabled.html.erb +0 -51
- data/app/views/spree/webhook_mailer/endpoint_disabled.text.erb +0 -10
- data/app/workflows/spree/fulfillments/purchase_label.rb +0 -40
- data/app/workflows/spree/returns/purchase_label.rb +0 -32
- data/lib/spree/analytics.rb +0 -11
- data/lib/spree/core/preferences/scoped_store.rb +0 -34
- data/lib/spree/core/preferences/store.rb +0 -105
- data/lib/spree/translation_migrations.rb +0 -52
|
@@ -8,10 +8,6 @@ module Spree
|
|
|
8
8
|
'customer_logged_in'
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def applicable?(promotable)
|
|
12
|
-
promotable.is_a?(Spree::Order) || promotable.is_a?(Spree::Cart)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
11
|
def eligible?(order, _options = {})
|
|
16
12
|
unless order.customer.present?
|
|
17
13
|
eligibility_errors.add(:base, eligibility_error_message(:no_user_specified))
|
|
@@ -87,6 +87,7 @@ module Spree
|
|
|
87
87
|
# `name` is whitelisted so the admin global search / command palette can
|
|
88
88
|
# filter via the `name_or_code_cont` predicate without a dedicated scope.
|
|
89
89
|
self.whitelisted_ransackable_attributes = ['name', 'path', 'promotion_category_id', 'code', 'kind', 'starts_at', 'expires_at']
|
|
90
|
+
search_by :name, :code
|
|
90
91
|
self.whitelisted_ransackable_associations = %w[coupon_codes]
|
|
91
92
|
|
|
92
93
|
def self.with_coupon_code(coupon_code)
|
|
@@ -106,6 +107,28 @@ module Spree
|
|
|
106
107
|
where('spree_promotions.expires_at IS NULL OR spree_promotions.expires_at > ?', Time.current)
|
|
107
108
|
end
|
|
108
109
|
|
|
110
|
+
# The promotion a purchase's PERSISTED coupon code names, which keeps it in
|
|
111
|
+
# candidacy even before it ever applied — the discount activates on the
|
|
112
|
+
# exact recalculation where the cart first qualifies, and deactivates the
|
|
113
|
+
# same way (Shopify-parity for cart-level discount codes). In-memory
|
|
114
|
+
# assignments deliberately don't participate: unsaved codes belong to
|
|
115
|
+
# the explicit PromotionHandler::Coupon path. A batch code counts only
|
|
116
|
+
# while the purchase holds it (see #eligible?).
|
|
117
|
+
#
|
|
118
|
+
# @param purchase [Spree::Cart, Spree::Order]
|
|
119
|
+
# @return [Array<Spree::Promotion>] empty, or the one promotion
|
|
120
|
+
def self.held_by_saved_coupon_code(purchase)
|
|
121
|
+
return [] unless purchase.class.respond_to?(:column_names) && purchase.class.column_names.include?('coupon_code')
|
|
122
|
+
|
|
123
|
+
code = purchase.read_attribute(:coupon_code)
|
|
124
|
+
return [] if code.blank?
|
|
125
|
+
|
|
126
|
+
promotion = purchase.store.promotions.active.with_coupon_code(code)
|
|
127
|
+
return [] if promotion.nil? || promotion.usage_limit_exceeded?(purchase)
|
|
128
|
+
|
|
129
|
+
[promotion]
|
|
130
|
+
end
|
|
131
|
+
|
|
109
132
|
def self.order_activatable?(promotable)
|
|
110
133
|
# Carts have no cancellation concept — only placed orders can be canceled.
|
|
111
134
|
promotable && !promotable.completed? && !(promotable.is_a?(Spree::Order) && promotable.canceled?)
|
|
@@ -202,7 +225,7 @@ module Spree
|
|
|
202
225
|
|
|
203
226
|
# called anytime order.recalculate_totals! happens
|
|
204
227
|
def eligible?(promotable, options = {})
|
|
205
|
-
return false if expired? || usage_limit_exceeded?(promotable) || blacklisted?(promotable)
|
|
228
|
+
return false if expired? || usage_limit_exceeded?(promotable) || blacklisted?(promotable) || !code_held_by?(promotable)
|
|
206
229
|
|
|
207
230
|
!!eligible_rules(promotable, options)
|
|
208
231
|
end
|
|
@@ -240,7 +263,7 @@ module Spree
|
|
|
240
263
|
end
|
|
241
264
|
|
|
242
265
|
def products
|
|
243
|
-
rules.where(type:
|
|
266
|
+
rules.where(type: 'Spree::Promotion::Rules::Product').map(&:products).flatten.uniq
|
|
244
267
|
end
|
|
245
268
|
|
|
246
269
|
def usage_limit_exceeded?(promotable)
|
|
@@ -278,9 +301,9 @@ module Spree
|
|
|
278
301
|
checkouts_credited(credits)
|
|
279
302
|
end
|
|
280
303
|
|
|
281
|
-
def line_item_actionable?(order, line_item)
|
|
282
|
-
if eligible?
|
|
283
|
-
rules = eligible_rules(order)
|
|
304
|
+
def line_item_actionable?(order, line_item, options = {})
|
|
305
|
+
if eligible?(order, options)
|
|
306
|
+
rules = eligible_rules(order, options)
|
|
284
307
|
if rules.blank?
|
|
285
308
|
true
|
|
286
309
|
else
|
|
@@ -325,6 +348,13 @@ module Spree
|
|
|
325
348
|
|
|
326
349
|
private
|
|
327
350
|
|
|
351
|
+
# A batch code discounts only the cart or order holding it, which is what
|
|
352
|
+
# keeps each generated code to a single order. A cart's line item has no
|
|
353
|
+
# order, and the adjuster has asked with the cart before pricing its lines.
|
|
354
|
+
def code_held_by?(order)
|
|
355
|
+
!multi_codes? || order.nil? || coupon_codes.held_by(order).exists?
|
|
356
|
+
end
|
|
357
|
+
|
|
328
358
|
# Counts distinct checkouts behind a set of discount rows.
|
|
329
359
|
#
|
|
330
360
|
# An order placed on its own is one checkout; the several orders a split
|
|
@@ -349,7 +379,7 @@ module Spree
|
|
|
349
379
|
def not_used?
|
|
350
380
|
return true if orders.empty?
|
|
351
381
|
|
|
352
|
-
errors.add(:base, :promotion_already_used, message:
|
|
382
|
+
errors.add(:base, :promotion_already_used, message: I18n.t('spree.promotion_already_used'))
|
|
353
383
|
throw(:abort)
|
|
354
384
|
end
|
|
355
385
|
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
# PromotionActions perform the necessary tasks when a promotion is activated by an event and determined to be eligible.
|
|
3
3
|
module Spree
|
|
4
4
|
class PromotionAction < Spree.base_class
|
|
5
|
+
include Spree::TypeLabels
|
|
6
|
+
|
|
7
|
+
self.type_labels_scope = 'spree.promotion_action_types'
|
|
8
|
+
|
|
5
9
|
has_prefix_id :pact
|
|
6
10
|
|
|
7
11
|
registers_subclasses_via { Spree.promotions.actions }
|
|
@@ -66,25 +70,14 @@ module Spree
|
|
|
66
70
|
when :line_item
|
|
67
71
|
%w[Spree::Promotion::Actions::CreateItemAdjustments Spree::Promotion::Actions::CreateLineItems]
|
|
68
72
|
when :fulfillment
|
|
69
|
-
%w[Spree::Promotion::Actions::FreeShipping
|
|
73
|
+
%w[Spree::Promotion::Actions::FreeShipping]
|
|
70
74
|
when :order
|
|
71
|
-
%w[Spree::Promotion::Actions::CreateAdjustment
|
|
75
|
+
%w[Spree::Promotion::Actions::CreateAdjustment]
|
|
72
76
|
else
|
|
73
77
|
[]
|
|
74
78
|
end
|
|
75
79
|
end
|
|
76
80
|
|
|
77
|
-
def self.human_name
|
|
78
|
-
Spree.t("promotion_action_types.#{api_type}.name", default: api_type.titleize)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def self.human_description
|
|
82
|
-
Spree.t("promotion_action_types.#{api_type}.description", default: '')
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def human_name = self.class.human_name
|
|
86
|
-
def human_description = self.class.human_description
|
|
87
|
-
|
|
88
81
|
# Returns the key of the promotion action
|
|
89
82
|
#
|
|
90
83
|
# @return [String] eg. free_shipping
|
|
@@ -109,7 +102,7 @@ module Spree
|
|
|
109
102
|
end
|
|
110
103
|
|
|
111
104
|
def label
|
|
112
|
-
|
|
105
|
+
I18n.t('spree.promotion_label', name: promotion.name)
|
|
113
106
|
end
|
|
114
107
|
end
|
|
115
108
|
end
|
|
@@ -4,6 +4,6 @@ module Spree
|
|
|
4
4
|
belongs_to :variant, class_name: 'Spree::Variant'
|
|
5
5
|
|
|
6
6
|
validates :quantity, presence: true
|
|
7
|
-
validates :quantity, numericality: { only_integer: true, message:
|
|
7
|
+
validates :quantity, numericality: { only_integer: true, message: I18n.t('spree.validation.must_be_int') }
|
|
8
8
|
end
|
|
9
9
|
end
|
|
@@ -39,7 +39,7 @@ module Spree
|
|
|
39
39
|
@status_code = :gift_card_not_applied
|
|
40
40
|
# The rejection message is what the hook author wrote for the
|
|
41
41
|
# shopper; fall back to the generic string if it says nothing.
|
|
42
|
-
@error = result.error.to_s.presence ||
|
|
42
|
+
@error = result.error.to_s.presence || I18n.t('spree.gift_card_not_applied')
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
|
@@ -57,9 +57,25 @@ module Spree
|
|
|
57
57
|
else
|
|
58
58
|
set_error_code :coupon_code_not_found
|
|
59
59
|
end
|
|
60
|
+
release_stale_coupon_codes
|
|
60
61
|
self
|
|
61
62
|
end
|
|
62
63
|
|
|
64
|
+
# Gives back every batch code this cart or order holds but no longer
|
|
65
|
+
# shows: anything other than the code it entered while that code waits
|
|
66
|
+
# to qualify, or the codes of promotions attached to it. Without this a
|
|
67
|
+
# replaced or dropped code stays held, and is spent with the order.
|
|
68
|
+
#
|
|
69
|
+
# @return [void]
|
|
70
|
+
def release_stale_coupon_codes
|
|
71
|
+
return unless order.persisted?
|
|
72
|
+
|
|
73
|
+
stale = Spree::CouponCode.unused.held_by(order).where.not(promotion_id: order.promotions.select(:id))
|
|
74
|
+
pending = order.coupon_code.to_s.downcase.presence if status_code == :coupon_code_not_eligible
|
|
75
|
+
stale = stale.where.not(code: pending) if pending
|
|
76
|
+
stale.find_each(&:remove_from_order)
|
|
77
|
+
end
|
|
78
|
+
|
|
63
79
|
def remove(coupon_code)
|
|
64
80
|
if gift_cards_enabled? && order.gift_card
|
|
65
81
|
result = order.remove_gift_card
|
|
@@ -75,19 +91,13 @@ module Spree
|
|
|
75
91
|
|
|
76
92
|
promotion = order.promotions.with_coupon_code(coupon_code)
|
|
77
93
|
if promotion.present?
|
|
78
|
-
# Order promotion has to be destroyed before line item removing
|
|
79
|
-
order.promotions.delete(promotion)
|
|
80
94
|
clear_persisted_coupon_code(coupon_code)
|
|
95
|
+
detach_promotion(promotion)
|
|
81
96
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
remove_promotion_adjustments(promotion)
|
|
89
|
-
remove_promotion_line_items(promotion)
|
|
90
|
-
order.recalculate_totals!
|
|
97
|
+
set_success_code :adjustments_deleted
|
|
98
|
+
elsif clear_persisted_coupon_code(coupon_code)
|
|
99
|
+
# Saved before the cart qualified, so no promotion is attached yet.
|
|
100
|
+
Spree::CouponCode.held_by(order).find_by(code: coupon_code.to_s.strip.downcase)&.remove_from_order
|
|
91
101
|
|
|
92
102
|
set_success_code :adjustments_deleted
|
|
93
103
|
else
|
|
@@ -96,14 +106,26 @@ module Spree
|
|
|
96
106
|
self
|
|
97
107
|
end
|
|
98
108
|
|
|
109
|
+
# Gives the code up to another cart or order that has taken it. Unlike
|
|
110
|
+
# #remove, the entered code stays on this one, so the shopper can be
|
|
111
|
+
# told it went (Spree::Cart#remove_unavailable_coupon_code!).
|
|
112
|
+
#
|
|
113
|
+
# @param coupon_code [String]
|
|
114
|
+
# @return [self]
|
|
115
|
+
def release(coupon_code)
|
|
116
|
+
promotion = order.promotions.with_coupon_code(coupon_code)
|
|
117
|
+
detach_promotion(promotion) if promotion.present?
|
|
118
|
+
self
|
|
119
|
+
end
|
|
120
|
+
|
|
99
121
|
def set_success_code(code)
|
|
100
122
|
@status_code = code
|
|
101
|
-
@success =
|
|
123
|
+
@success = I18n.t("spree.#{code}")
|
|
102
124
|
end
|
|
103
125
|
|
|
104
126
|
def set_error_code(code, locale_options = {})
|
|
105
127
|
@status_code = code
|
|
106
|
-
@error =
|
|
128
|
+
@error = I18n.t("spree.#{code}", **locale_options)
|
|
107
129
|
end
|
|
108
130
|
|
|
109
131
|
# Returns the promotion for the order
|
|
@@ -143,6 +165,21 @@ module Spree
|
|
|
143
165
|
order.update_column(:coupon_code, nil)
|
|
144
166
|
end
|
|
145
167
|
|
|
168
|
+
def detach_promotion(promotion)
|
|
169
|
+
# Order promotion has to be destroyed before line item removing
|
|
170
|
+
order.promotions.delete(promotion)
|
|
171
|
+
|
|
172
|
+
if promotion.multi_codes?
|
|
173
|
+
promotion.coupon_codes.held_by(order).first&.remove_from_order
|
|
174
|
+
else
|
|
175
|
+
promotion.touch
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
remove_promotion_adjustments(promotion)
|
|
179
|
+
remove_promotion_line_items(promotion)
|
|
180
|
+
order.recalculate_totals!
|
|
181
|
+
end
|
|
182
|
+
|
|
146
183
|
def remove_promotion_adjustments(promotion)
|
|
147
184
|
order.discounts.where(promotion_action_id: promotion.actions.pluck(:id)).destroy_all
|
|
148
185
|
end
|
|
@@ -165,6 +202,11 @@ module Spree
|
|
|
165
202
|
return set_error_code :coupon_code_used if promotion.coupon_codes.used.where(code: order.coupon_code).exists?
|
|
166
203
|
return promotion_usage_limit_exceeded if promotion.usage_limit_exceeded?(order)
|
|
167
204
|
|
|
205
|
+
# Claimed before anything prices the code, since the adjuster only
|
|
206
|
+
# discounts the holder, and a cart that qualifies later activates the
|
|
207
|
+
# code on recalculation without coming back here.
|
|
208
|
+
return set_error_code :coupon_code_used unless claim_coupon_code(order.coupon_code.downcase)
|
|
209
|
+
|
|
168
210
|
unless promotion.eligible?(order, options)
|
|
169
211
|
# Rules that explain themselves keep their message, but the status
|
|
170
212
|
# code is always :coupon_code_not_eligible so callers can park the
|
|
@@ -216,11 +258,6 @@ module Spree
|
|
|
216
258
|
end
|
|
217
259
|
|
|
218
260
|
if discount || created_line_items
|
|
219
|
-
if discount && !claim_coupon_code(discount, coupon_code)
|
|
220
|
-
release_coupon_code(order, coupon_code)
|
|
221
|
-
return set_error_code :coupon_code_used
|
|
222
|
-
end
|
|
223
|
-
|
|
224
261
|
order.recalculate_totals!
|
|
225
262
|
set_success_code :coupon_code_applied
|
|
226
263
|
elsif order.promotions.with_coupon_code(order.coupon_code)
|
|
@@ -249,8 +286,8 @@ module Spree
|
|
|
249
286
|
# them in, so the two serialize instead of deadlocking.
|
|
250
287
|
#
|
|
251
288
|
# @return [Boolean] false when the code can no longer be claimed
|
|
252
|
-
def claim_coupon_code(
|
|
253
|
-
record =
|
|
289
|
+
def claim_coupon_code(coupon_code)
|
|
290
|
+
record = promotion.coupon_codes.find_by(code: coupon_code)
|
|
254
291
|
return true if record.nil?
|
|
255
292
|
|
|
256
293
|
holder = record.holder
|
|
@@ -261,16 +298,11 @@ module Spree
|
|
|
261
298
|
record.lock!
|
|
262
299
|
next false if record.used? || !same_holder?(record.holder, holder) || !releasable?(holder)
|
|
263
300
|
|
|
264
|
-
|
|
301
|
+
self.class.new(holder).release(coupon_code) if holder
|
|
265
302
|
record.apply_order!(order)
|
|
266
303
|
end
|
|
267
304
|
end
|
|
268
305
|
|
|
269
|
-
# Gift cards are turned off so a holder paying with one keeps it.
|
|
270
|
-
def release_coupon_code(holder, coupon_code)
|
|
271
|
-
self.class.new(holder, enable_gift_cards: false).remove(coupon_code)
|
|
272
|
-
end
|
|
273
|
-
|
|
274
306
|
def releasable?(holder)
|
|
275
307
|
return true if holder.nil?
|
|
276
308
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Base class for all promotion rules
|
|
2
2
|
module Spree
|
|
3
3
|
class PromotionRule < Spree.base_class
|
|
4
|
+
include Spree::TypeLabels
|
|
5
|
+
|
|
6
|
+
self.type_labels_scope = 'spree.promotion_rule_types'
|
|
7
|
+
|
|
4
8
|
has_prefix_id :prorule
|
|
5
9
|
|
|
6
10
|
registers_subclasses_via { Spree.promotions.rules }
|
|
@@ -17,8 +21,8 @@ module Spree
|
|
|
17
21
|
all.select { |rule| rule.applicable?(promotable) }
|
|
18
22
|
end
|
|
19
23
|
|
|
20
|
-
def applicable?(
|
|
21
|
-
|
|
24
|
+
def applicable?(promotable)
|
|
25
|
+
promotable.is_a?(Spree::Order) || promotable.is_a?(Spree::Cart)
|
|
22
26
|
end
|
|
23
27
|
|
|
24
28
|
def eligible?(_promotable, _options = {})
|
|
@@ -35,17 +39,6 @@ module Spree
|
|
|
35
39
|
@eligibility_errors ||= ActiveModel::Errors.new(self)
|
|
36
40
|
end
|
|
37
41
|
|
|
38
|
-
def self.human_name
|
|
39
|
-
Spree.t("promotion_rule_types.#{api_type}.name", default: api_type.titleize)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def self.human_description
|
|
43
|
-
Spree.t("promotion_rule_types.#{api_type}.description", default: '')
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def human_name = self.class.human_name
|
|
47
|
-
def human_description = self.class.human_description
|
|
48
|
-
|
|
49
42
|
# Returns the key of the promotion rule
|
|
50
43
|
#
|
|
51
44
|
# @return [String] eg. currency
|
|
@@ -70,7 +63,7 @@ module Spree
|
|
|
70
63
|
end
|
|
71
64
|
|
|
72
65
|
def eligibility_error_message(key, options = {})
|
|
73
|
-
|
|
66
|
+
I18n.t("spree.eligibility_errors.messages.#{key}", **options)
|
|
74
67
|
end
|
|
75
68
|
end
|
|
76
69
|
end
|
|
@@ -26,6 +26,7 @@ module Spree
|
|
|
26
26
|
include Spree::Metadata
|
|
27
27
|
|
|
28
28
|
publishes_lifecycle_events
|
|
29
|
+
publishes_events :canceled, :draft, :ordered, :partially_received, :over_received, :received
|
|
29
30
|
|
|
30
31
|
has_status :draft, :ordered, :partially_received, :received, :over_received, :canceled,
|
|
31
32
|
default: :draft
|
|
@@ -57,7 +58,9 @@ module Spree
|
|
|
57
58
|
self.whitelisted_ransackable_attributes = %w[number status currency reference expected_at
|
|
58
59
|
cancel_by ordered_at received_at closed_short_at
|
|
59
60
|
supplier_id destination_location_id created_at]
|
|
61
|
+
search_by :number, :reference
|
|
60
62
|
self.whitelisted_ransackable_scopes = %w[open closed overdue past_cancel_by]
|
|
63
|
+
self.ransackable_scope_types = %w[open closed overdue past_cancel_by].index_with('boolean')
|
|
61
64
|
self.whitelisted_ransackable_associations = %w[supplier destination_location items]
|
|
62
65
|
|
|
63
66
|
# What the supplier will invoice for everything ordered.
|
|
@@ -83,7 +83,7 @@ module Spree
|
|
|
83
83
|
def violation_message(name, quantity)
|
|
84
84
|
return nil if satisfied_by?(quantity)
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
I18n.t('spree.cart_line_item.quantity_rule_violated',
|
|
87
87
|
li_name: name, quantities: nearest_valid(quantity).to_sentence)
|
|
88
88
|
end
|
|
89
89
|
|
data/app/models/spree/refund.rb
CHANGED
|
@@ -5,6 +5,9 @@ module Spree
|
|
|
5
5
|
include Spree::ActedBy
|
|
6
6
|
include Spree::HasCustomFields
|
|
7
7
|
include Spree::Metadata
|
|
8
|
+
include Spree::CanonicalDecimals
|
|
9
|
+
|
|
10
|
+
canonical_decimals :amount
|
|
8
11
|
include Spree::InstrumentsGatewayCalls
|
|
9
12
|
if defined?(Spree::Security::Refunds)
|
|
10
13
|
include Spree::Security::Refunds
|
|
@@ -33,6 +36,20 @@ module Spree
|
|
|
33
36
|
validate :amount_is_less_than_or_equal_to_allowed_amount, on: :create, if: :amount
|
|
34
37
|
validate :order_is_covered_by_payment, on: :create
|
|
35
38
|
|
|
39
|
+
# Refunds for goods that came back, which settle what the customer owed
|
|
40
|
+
# for them rather than leaving it owed again.
|
|
41
|
+
scope :for_returned_items, -> { where(originator_type: returned_item_originators) }
|
|
42
|
+
|
|
43
|
+
# @return [Array<String>]
|
|
44
|
+
def self.returned_item_originators
|
|
45
|
+
[Spree::Return, Spree::Claim, Spree::Exchange].map(&:polymorphic_name)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [Boolean]
|
|
49
|
+
def for_returned_items?
|
|
50
|
+
self.class.returned_item_originators.include?(originator_type)
|
|
51
|
+
end
|
|
52
|
+
|
|
36
53
|
attr_reader :response
|
|
37
54
|
|
|
38
55
|
delegate :currency, to: :payment
|
|
@@ -42,10 +59,6 @@ module Spree
|
|
|
42
59
|
# back through a payment that may belong to several orders.
|
|
43
60
|
before_validation :assign_order_from_payment, on: :create
|
|
44
61
|
|
|
45
|
-
def amount=(amount)
|
|
46
|
-
self[:amount] = Spree::LocalizedNumber.parse(amount)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
62
|
def money
|
|
50
63
|
Spree::Money.new(amount, currency: currency)
|
|
51
64
|
end
|
|
@@ -76,6 +89,17 @@ module Spree
|
|
|
76
89
|
originator.refunded_line_amounts
|
|
77
90
|
end
|
|
78
91
|
|
|
92
|
+
# The tax inside {#refunded_line_amounts}, for the lines whose tax is known.
|
|
93
|
+
# A line opened before returns and claims carried tax is absent: its amount
|
|
94
|
+
# says nothing about how much of it was tax.
|
|
95
|
+
#
|
|
96
|
+
# @return [Hash{Integer => BigDecimal}] line item id => tax
|
|
97
|
+
def refunded_line_taxes
|
|
98
|
+
return {} unless originator.respond_to?(:refunded_line_taxes)
|
|
99
|
+
|
|
100
|
+
originator.refunded_line_taxes
|
|
101
|
+
end
|
|
102
|
+
|
|
79
103
|
# Returns true if the refund is editable.
|
|
80
104
|
#
|
|
81
105
|
# Read through the refund's own order: a payment shared by a split checkout
|
|
@@ -96,9 +120,7 @@ module Spree
|
|
|
96
120
|
def perform!
|
|
97
121
|
return true if transaction_id.present?
|
|
98
122
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
@response = process!(credit_cents)
|
|
123
|
+
@response = process!(payment.payment_method.gateway_amount(amount, currency))
|
|
102
124
|
|
|
103
125
|
self.transaction_id = @response.authorization
|
|
104
126
|
update_columns(transaction_id: transaction_id)
|
|
@@ -141,37 +163,38 @@ module Spree
|
|
|
141
163
|
end
|
|
142
164
|
|
|
143
165
|
# return a payment response object if successful or else raise an error
|
|
144
|
-
|
|
145
|
-
|
|
166
|
+
# @param credit_amount [Spree::Money, Integer] as PaymentMethod#gateway_amount returns it
|
|
167
|
+
def process!(credit_amount)
|
|
168
|
+
refund_total = calculate_refund_amount(credit_amount)
|
|
146
169
|
|
|
147
170
|
response = instrument_gateway_call(:credit, payment.payment_method) do
|
|
148
171
|
if payment.payment_method.payment_profiles_supported?
|
|
149
|
-
payment.payment_method.credit(
|
|
172
|
+
payment.payment_method.credit(refund_total, payment.source, payment.transaction_id, originator: self)
|
|
150
173
|
else
|
|
151
|
-
payment.payment_method.credit(
|
|
174
|
+
payment.payment_method.credit(refund_total, payment.transaction_id, originator: self)
|
|
152
175
|
end
|
|
153
176
|
end
|
|
154
177
|
|
|
155
178
|
if response.success?
|
|
156
|
-
track_order_as_refunded(
|
|
179
|
+
track_order_as_refunded(refund_total)
|
|
157
180
|
else
|
|
158
|
-
Rails.logger.error(
|
|
181
|
+
Rails.logger.error(I18n.t('spree.gateway_error') + " #{response.to_yaml}")
|
|
159
182
|
text = response.params['message'] || response.params['response_reason_text'] || response.message
|
|
160
183
|
raise Core::GatewayError, text
|
|
161
184
|
end
|
|
162
185
|
|
|
163
186
|
response
|
|
164
187
|
rescue Spree::PaymentConnectionError => e
|
|
165
|
-
Rails.logger.error(
|
|
166
|
-
raise Core::GatewayError,
|
|
188
|
+
Rails.logger.error(I18n.t('spree.gateway_error') + " #{e.inspect}")
|
|
189
|
+
raise Core::GatewayError, I18n.t('spree.unable_to_connect_to_gateway')
|
|
167
190
|
end
|
|
168
191
|
|
|
169
|
-
def calculate_refund_amount(
|
|
192
|
+
def calculate_refund_amount(credit_amount)
|
|
170
193
|
# Overwrite this for more complex calculations
|
|
171
|
-
|
|
194
|
+
credit_amount
|
|
172
195
|
end
|
|
173
196
|
|
|
174
|
-
def track_order_as_refunded(
|
|
197
|
+
def track_order_as_refunded(credit_amount)
|
|
175
198
|
# You can track refunds here
|
|
176
199
|
end
|
|
177
200
|
|
data/app/models/spree/return.rb
CHANGED
|
@@ -20,13 +20,14 @@ module Spree
|
|
|
20
20
|
include Spree::HasStatus
|
|
21
21
|
include Spree::HasCustomFields
|
|
22
22
|
include Spree::Metadata
|
|
23
|
+
include Spree::PostSale::Taxation
|
|
23
24
|
|
|
24
25
|
publishes_lifecycle_events
|
|
26
|
+
publishes_events :approved, :canceled, :received, :refunded, :requested
|
|
25
27
|
|
|
26
28
|
has_status :requested, :approved, :received, :refunded, :canceled,
|
|
27
29
|
default: :requested
|
|
28
30
|
|
|
29
|
-
belongs_to :store, class_name: 'Spree::Store'
|
|
30
31
|
belongs_to :order, class_name: 'Spree::Order', inverse_of: :returns
|
|
31
32
|
belongs_to :stock_location, class_name: 'Spree::StockLocation'
|
|
32
33
|
belongs_to :reason, class_name: 'Spree::ReturnReason', optional: true, inverse_of: :returns
|
|
@@ -51,6 +52,7 @@ module Spree
|
|
|
51
52
|
delegate :currency, to: :order
|
|
52
53
|
|
|
53
54
|
self.whitelisted_ransackable_attributes = %w[number status created_at]
|
|
55
|
+
search_by :number
|
|
54
56
|
self.whitelisted_ransackable_associations = %w[order reason]
|
|
55
57
|
|
|
56
58
|
# The label that currently binds the inbound parcel — bought or uploaded,
|
|
@@ -118,11 +120,16 @@ module Spree
|
|
|
118
120
|
received? || refunded?
|
|
119
121
|
end
|
|
120
122
|
|
|
121
|
-
# What the customer is owed for the items being returned.
|
|
123
|
+
# What the customer is owed for the items being returned, tax included.
|
|
122
124
|
def refund_total
|
|
123
125
|
return_line_items.sum(&:refund_amount)
|
|
124
126
|
end
|
|
125
127
|
|
|
128
|
+
# The tax inside {#refund_total}.
|
|
129
|
+
def refund_tax_total
|
|
130
|
+
return_line_items.sum(&:refund_tax_amount)
|
|
131
|
+
end
|
|
132
|
+
|
|
126
133
|
# What a refund from this return paid for, line by line. Only ever what
|
|
127
134
|
# the warehouse counted: the seller's clawback is built from this, and a
|
|
128
135
|
# line nobody counted earned nothing back.
|
|
@@ -139,6 +146,20 @@ module Spree
|
|
|
139
146
|
end
|
|
140
147
|
end
|
|
141
148
|
|
|
149
|
+
# The tax inside {#refunded_line_amounts}, for the lines whose tax is
|
|
150
|
+
# recorded.
|
|
151
|
+
#
|
|
152
|
+
# @return [Hash{Integer => BigDecimal}] line item id => tax
|
|
153
|
+
def refunded_line_taxes
|
|
154
|
+
return {} unless counted?
|
|
155
|
+
|
|
156
|
+
return_line_items.each_with_object(Hash.new(0)) do |line, taxes|
|
|
157
|
+
next if line.refund_amount.zero? || !line.settles_tax?
|
|
158
|
+
|
|
159
|
+
taxes[line.line_item_id] += line.refund_tax_amount
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
142
163
|
# What has actually been refunded so far — a return can be refunded in
|
|
143
164
|
# more than one step (part to store credit, part to the card), and store
|
|
144
165
|
# credit is its own ledger rather than a Spree::Refund row.
|
|
@@ -157,5 +178,13 @@ module Spree
|
|
|
157
178
|
def display_refunded_total
|
|
158
179
|
Spree::Money.new(refunded_total, currency: currency)
|
|
159
180
|
end
|
|
181
|
+
|
|
182
|
+
def display_refund_tax_total
|
|
183
|
+
Spree::Money.new(refund_tax_total, currency: currency)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def taxed_lines
|
|
187
|
+
return_line_items
|
|
188
|
+
end
|
|
160
189
|
end
|
|
161
190
|
end
|