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
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Purchase
|
|
3
|
+
# One-release bridges for the names renamed in 6.0, shared by
|
|
4
|
+
# {Spree::Cart} and {Spree::Order}. Before 6.0 a cart was an incomplete
|
|
5
|
+
# order, so extensions written against 5.x (payment gateways, checkout
|
|
6
|
+
# plugins) call the legacy names on carts too. Every legacy name warns and
|
|
7
|
+
# forwards to its replacement. Removed in 6.1.
|
|
8
|
+
#
|
|
9
|
+
# Renamed columns are also registered with +alias_attribute+, so the legacy
|
|
10
|
+
# name keeps working in +where+ / +find_by+ (those paths do not warn).
|
|
11
|
+
module DeprecatedAliases
|
|
12
|
+
extend ActiveSupport::Concern
|
|
13
|
+
|
|
14
|
+
RENAMED_ATTRIBUTES = {
|
|
15
|
+
promo_total: :discount_total,
|
|
16
|
+
item_count: :total_quantity,
|
|
17
|
+
shipment_total: :delivery_total,
|
|
18
|
+
ship_total: :delivery_total,
|
|
19
|
+
special_instructions: :customer_note
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
RENAMED_METHODS = {
|
|
23
|
+
display_promo_total: :display_discount_total,
|
|
24
|
+
display_shipment_total: :display_delivery_total,
|
|
25
|
+
display_ship_total: :display_delivery_total,
|
|
26
|
+
shipping_discount: :fulfillment_discount,
|
|
27
|
+
delivery_required?: :delivery_step_required?,
|
|
28
|
+
requires_ship_address?: :shipping_address_required?,
|
|
29
|
+
set_shipments_cost: :set_fulfillments_cost,
|
|
30
|
+
ensure_updated_shipments: :ensure_updated_fulfillments,
|
|
31
|
+
create_proposed_fulfillments: :rebuild_fulfillments!,
|
|
32
|
+
create_proposed_shipments: :rebuild_fulfillments!,
|
|
33
|
+
associate_user!: :associate_customer!,
|
|
34
|
+
update_with_updater!: :recalculate_totals!,
|
|
35
|
+
all_line_items: :line_items
|
|
36
|
+
}.freeze
|
|
37
|
+
|
|
38
|
+
# 5.x took a store argument; payment methods now always come from the
|
|
39
|
+
# purchase's own store.
|
|
40
|
+
RENAMED_PAYMENT_METHOD_READERS = %i[
|
|
41
|
+
available_payment_methods
|
|
42
|
+
collect_payment_methods
|
|
43
|
+
collect_frontend_payment_methods
|
|
44
|
+
].freeze
|
|
45
|
+
|
|
46
|
+
included do
|
|
47
|
+
include Spree::DeprecatedCustomerAlias
|
|
48
|
+
|
|
49
|
+
RENAMED_ATTRIBUTES.each do |legacy_name, current_name|
|
|
50
|
+
alias_attribute legacy_name, current_name
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
RENAMED_ATTRIBUTES.each do |legacy_name, current_name|
|
|
55
|
+
define_method(legacy_name) do
|
|
56
|
+
warn_deprecated_name(legacy_name, current_name)
|
|
57
|
+
public_send(current_name)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
define_method(:"#{legacy_name}=") do |value|
|
|
61
|
+
warn_deprecated_name(:"#{legacy_name}=", :"#{current_name}=")
|
|
62
|
+
public_send(:"#{current_name}=", value)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
RENAMED_METHODS.each do |legacy_name, current_name|
|
|
67
|
+
define_method(legacy_name) do |*args, **options, &block|
|
|
68
|
+
warn_deprecated_name(legacy_name, current_name)
|
|
69
|
+
public_send(current_name, *args, **options, &block)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
RENAMED_PAYMENT_METHOD_READERS.each do |legacy_name|
|
|
74
|
+
define_method(legacy_name) do |*|
|
|
75
|
+
warn_deprecated_name(legacy_name, :payment_methods)
|
|
76
|
+
payment_methods
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def warn_deprecated_name(legacy_name, current_name)
|
|
83
|
+
Spree::Deprecation.warn("#{self.class.name}##{legacy_name} is deprecated and will be removed in Spree 6.1. Use ##{current_name} instead.")
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -51,16 +51,22 @@ module Spree
|
|
|
51
51
|
|
|
52
52
|
payment = payments.checkout.store_credits.where(source: gift_card.store_credits).first
|
|
53
53
|
return unless payment
|
|
54
|
+
# Nothing is left for the card to pay, and a store credit cannot hold
|
|
55
|
+
# a zero amount, so the card is released rather than resized.
|
|
56
|
+
return remove_gift_card unless total.positive?
|
|
54
57
|
|
|
55
58
|
gift_card.with_lock do
|
|
56
|
-
|
|
59
|
+
# A locking read: a plain reload can return the transaction's older
|
|
60
|
+
# snapshot, and a resize committed since would be applied again.
|
|
61
|
+
payment.lock!
|
|
62
|
+
new_amount = [gift_card.spendable_amount + payment.amount, total].min
|
|
57
63
|
next if payment.amount == new_amount
|
|
58
64
|
|
|
59
65
|
difference = new_amount - payment.amount
|
|
60
|
-
# update_column bypasses Payment#max_amount validation which can
|
|
61
|
-
# fail on stale in-memory state; bounds enforced via min() above.
|
|
62
|
-
payment.update_column(:amount, new_amount)
|
|
63
66
|
payment.source.update_column(:amount, new_amount)
|
|
67
|
+
# Skips Payment#max_amount, which can fail on stale in-memory state;
|
|
68
|
+
# min() above bounds the amount.
|
|
69
|
+
payment.update_store_credit_amount!(new_amount)
|
|
64
70
|
gift_card.amount_used += difference
|
|
65
71
|
gift_card.save!
|
|
66
72
|
end
|
|
@@ -22,7 +22,7 @@ module Spree
|
|
|
22
22
|
return if locale.blank? || store.blank?
|
|
23
23
|
|
|
24
24
|
unless store.supported_locales_list.include?(locale)
|
|
25
|
-
errors.add(:locale, :locale_not_supported_by_store, message:
|
|
25
|
+
errors.add(:locale, :locale_not_supported_by_store, message: I18n.t('spree.locale_not_supported_by_store'))
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
end
|
|
@@ -31,18 +31,22 @@ module Spree
|
|
|
31
31
|
payments.pending
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
# Active front-end payment methods available for this record.
|
|
34
|
+
# Active front-end payment methods available for this record. Store
|
|
35
|
+
# credit is never one of them: it is applied through its own endpoint
|
|
36
|
+
# before the buyer chooses how to pay the rest.
|
|
35
37
|
#
|
|
36
38
|
# @return [Array<Spree::PaymentMethod>]
|
|
37
39
|
def payment_methods
|
|
38
|
-
store.payment_methods.active.storefront_visible.select
|
|
40
|
+
store.payment_methods.active.storefront_visible.select do |payment_method|
|
|
41
|
+
!payment_method.store_credit? && payment_method.available_for_order?(self)
|
|
42
|
+
end
|
|
39
43
|
end
|
|
40
44
|
|
|
41
45
|
# Free checkouts have no money to collect.
|
|
42
46
|
#
|
|
43
47
|
# @return [Boolean]
|
|
44
48
|
def payment_required?
|
|
45
|
-
total.
|
|
49
|
+
total.to_d.positive?
|
|
46
50
|
end
|
|
47
51
|
|
|
48
52
|
# Whether a confirm/review pass is expected before completion —
|
|
@@ -71,7 +75,7 @@ module Spree
|
|
|
71
75
|
# Don't run if there are authorized payments
|
|
72
76
|
return if pending_payments.any? && unprocessed_payments.empty?
|
|
73
77
|
# Never complete without a successfully processed payment.
|
|
74
|
-
raise Spree::Core::GatewayError,
|
|
78
|
+
raise Spree::Core::GatewayError, I18n.t('spree.no_payment_found') if unprocessed_payments.empty?
|
|
75
79
|
|
|
76
80
|
unprocessed_payments.each do |payment|
|
|
77
81
|
break if settled_payment_total >= total
|
|
@@ -17,8 +17,8 @@ module Spree
|
|
|
17
17
|
MAX_PO_DOCUMENT_SIZE = 10.megabytes
|
|
18
18
|
|
|
19
19
|
# What a purchase order plausibly arrives as: an export from the buyer's
|
|
20
|
-
# procurement system, a scan, or a photo of
|
|
21
|
-
#
|
|
20
|
+
# procurement system (often a spreadsheet or CSV), a scan, or a photo of
|
|
21
|
+
# one.
|
|
22
22
|
PO_DOCUMENT_CONTENT_TYPES = %w[
|
|
23
23
|
application/pdf
|
|
24
24
|
image/jpeg
|
|
@@ -27,6 +27,10 @@ module Spree
|
|
|
27
27
|
image/webp
|
|
28
28
|
application/msword
|
|
29
29
|
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
|
30
|
+
application/vnd.ms-excel
|
|
31
|
+
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
|
32
|
+
application/vnd.oasis.opendocument.spreadsheet
|
|
33
|
+
text/csv
|
|
30
34
|
].freeze
|
|
31
35
|
|
|
32
36
|
included do
|
|
@@ -36,6 +40,7 @@ module Spree
|
|
|
36
40
|
# internal cost codes, and is served only through an authenticated
|
|
37
41
|
# download action.
|
|
38
42
|
has_one_attached :po_document, service: Spree.private_storage_service_name
|
|
43
|
+
signed_id_attachments :po_document
|
|
39
44
|
|
|
40
45
|
validates :po_document,
|
|
41
46
|
size: { less_than_or_equal_to: MAX_PO_DOCUMENT_SIZE },
|
|
@@ -83,8 +88,8 @@ module Spree
|
|
|
83
88
|
return if stored_size <= MAX_PO_DOCUMENT_SIZE
|
|
84
89
|
|
|
85
90
|
errors.add(
|
|
86
|
-
:po_document, :po_document_too_large, message:
|
|
87
|
-
|
|
91
|
+
:po_document, :po_document_too_large, message: I18n.t(
|
|
92
|
+
'spree.po_document_too_large',
|
|
88
93
|
size: ActiveSupport::NumberHelper.number_to_human_size(MAX_PO_DOCUMENT_SIZE)
|
|
89
94
|
)
|
|
90
95
|
)
|
|
@@ -58,7 +58,7 @@ module Spree
|
|
|
58
58
|
|
|
59
59
|
# @return [BigDecimal]
|
|
60
60
|
def total_applied_store_credit
|
|
61
|
-
if payments
|
|
61
|
+
if read_association_in_memory?(:payments)
|
|
62
62
|
payments.
|
|
63
63
|
find_all(&:store_credit?).
|
|
64
64
|
reject(&:has_invalid_status?).
|
|
@@ -68,10 +68,32 @@ module Spree
|
|
|
68
68
|
end
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
+
# Balance still to collect, never negative. Store credit already applied
|
|
72
|
+
# but not yet captured is taken off; captured credit is a completed
|
|
73
|
+
# payment, so the balance has counted it already.
|
|
74
|
+
#
|
|
75
|
+
# @return [BigDecimal]
|
|
76
|
+
def amount_due
|
|
77
|
+
[outstanding_balance - uncaptured_store_credit, 0].max
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# What store credit paid, apart from gift cards. A gift card is redeemed
|
|
81
|
+
# as store credit, but it is reported on its own as +gift_card_total+, so
|
|
82
|
+
# a summary showing both rows deducts each amount once.
|
|
83
|
+
#
|
|
84
|
+
# @return [BigDecimal]
|
|
85
|
+
def store_credit_total
|
|
86
|
+
total_applied_store_credit - gift_card_total
|
|
87
|
+
end
|
|
88
|
+
|
|
71
89
|
def using_store_credit?
|
|
72
90
|
total_applied_store_credit > 0
|
|
73
91
|
end
|
|
74
92
|
|
|
93
|
+
def display_store_credit_total
|
|
94
|
+
Spree::Money.new(-store_credit_total, currency: currency)
|
|
95
|
+
end
|
|
96
|
+
|
|
75
97
|
def display_total_applicable_store_credit
|
|
76
98
|
Spree::Money.new(-total_applicable_store_credit, currency: currency)
|
|
77
99
|
end
|
|
@@ -95,6 +117,19 @@ module Spree
|
|
|
95
117
|
def display_total_minus_store_credits
|
|
96
118
|
Spree::Money.new(total_minus_store_credits, currency: currency)
|
|
97
119
|
end
|
|
120
|
+
|
|
121
|
+
private
|
|
122
|
+
|
|
123
|
+
# @return [BigDecimal]
|
|
124
|
+
def uncaptured_store_credit
|
|
125
|
+
if read_association_in_memory?(:payments)
|
|
126
|
+
payments.
|
|
127
|
+
select { |payment| payment.store_credit? && !payment.has_invalid_status? && !payment.completed? }.
|
|
128
|
+
sum(BigDecimal('0'), &:amount)
|
|
129
|
+
else
|
|
130
|
+
payments.store_credits.valid.where.not(status: 'completed').sum(:amount)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
98
133
|
end
|
|
99
134
|
end
|
|
100
135
|
end
|
|
@@ -10,9 +10,37 @@ module Spree
|
|
|
10
10
|
line_items.sum(:quantity)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
# What promotion calculators take a share of: the line amounts less the
|
|
14
|
+
# free gifts, so a gift never enlarges a percentage off the order.
|
|
15
|
+
#
|
|
13
16
|
# @return [BigDecimal]
|
|
14
17
|
def amount
|
|
15
|
-
line_items.sum(BigDecimal('0'), &:amount)
|
|
18
|
+
line_items.sum(BigDecimal('0'), &:amount) - gift_amount
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# The list price of the units gift promotions give away. The gift keeps
|
|
22
|
+
# its price on its line and is paid for by a discount, so anything
|
|
23
|
+
# measuring what the shopper spends has to take it out.
|
|
24
|
+
#
|
|
25
|
+
# @param promotion [Spree::Promotion, nil] the promotion doing the
|
|
26
|
+
# measuring; its own gifts are always taken out, since a gift cannot
|
|
27
|
+
# be what qualifies the promotion giving it away
|
|
28
|
+
# @param own_gift_only [Boolean] true while deciding whether another
|
|
29
|
+
# promotion gives its gift, so two gift promotions with spend
|
|
30
|
+
# thresholds do not each wait on the other
|
|
31
|
+
# @return [BigDecimal]
|
|
32
|
+
def gift_amount(promotion: nil, own_gift_only: false)
|
|
33
|
+
return BigDecimal('0') if line_items.empty?
|
|
34
|
+
|
|
35
|
+
excluded_gift_promo_actions = gift_promo_actions(promotion, own_gift_only).select do |action|
|
|
36
|
+
action.promotion_id == promotion&.id || action.gives_away?(self)
|
|
37
|
+
end
|
|
38
|
+
return BigDecimal('0') if excluded_gift_promo_actions.empty?
|
|
39
|
+
|
|
40
|
+
line_items.sum(BigDecimal('0')) do |line_item|
|
|
41
|
+
gifted_quantity = excluded_gift_promo_actions.sum { |action| action.gifted_quantity_of(line_item) }
|
|
42
|
+
Spree::Money::Rounding.to_currency(line_item.price * [gifted_quantity, line_item.quantity].min, line_item.currency)
|
|
43
|
+
end
|
|
16
44
|
end
|
|
17
45
|
|
|
18
46
|
# Re-sums what the customer has actually paid, and nothing else. A
|
|
@@ -47,13 +75,6 @@ module Spree
|
|
|
47
75
|
outstanding_balance != 0
|
|
48
76
|
end
|
|
49
77
|
|
|
50
|
-
# Balance still to collect after applied store credit, never negative.
|
|
51
|
-
#
|
|
52
|
-
# @return [BigDecimal]
|
|
53
|
-
def amount_due
|
|
54
|
-
[outstanding_balance - total_applied_store_credit, 0].max
|
|
55
|
-
end
|
|
56
|
-
|
|
57
78
|
# @return [Boolean]
|
|
58
79
|
def paid?
|
|
59
80
|
total.positive? && payment_total >= total
|
|
@@ -78,6 +99,26 @@ module Spree
|
|
|
78
99
|
|
|
79
100
|
private
|
|
80
101
|
|
|
102
|
+
# Other promotions' gifts are looked for among the promotions a
|
|
103
|
+
# recalculation writes discounts for, so a gift leaves the measure
|
|
104
|
+
# exactly when its discount can be written.
|
|
105
|
+
def gift_promo_actions(promotion, own_gift_only)
|
|
106
|
+
own = promotion ? promotion.actions.grep(Spree::Promotion::Actions::CreateLineItems) : []
|
|
107
|
+
return own if own_gift_only
|
|
108
|
+
|
|
109
|
+
discounting_ids = promotion_ids + Spree::Promotion.held_by_saved_coupon_code(self).map(&:id)
|
|
110
|
+
return own if discounting_ids.empty?
|
|
111
|
+
|
|
112
|
+
gifting_cart_variants = Spree::PromotionActionLineItem.
|
|
113
|
+
where(variant_id: line_items.map(&:variant_id)).
|
|
114
|
+
select(:promotion_action_id)
|
|
115
|
+
others = Spree::Promotion::Actions::CreateLineItems.
|
|
116
|
+
where(promotion_id: discounting_ids, id: gifting_cart_variants).
|
|
117
|
+
includes(:promotion, :promotion_action_line_items)
|
|
118
|
+
|
|
119
|
+
(own + others.to_a).uniq(&:id)
|
|
120
|
+
end
|
|
121
|
+
|
|
81
122
|
# Completed payments less their refunds, as a scalar subquery so the
|
|
82
123
|
# sum and the write are one statement.
|
|
83
124
|
#
|
|
@@ -11,6 +11,12 @@ module Spree::RansackableAttributes
|
|
|
11
11
|
class_attribute :whitelisted_ransackable_attributes
|
|
12
12
|
class_attribute :whitelisted_ransackable_scopes
|
|
13
13
|
|
|
14
|
+
# `{ 'price_between' => %w[decimal decimal], 'in_categories' => { list: 'id' } }`
|
|
15
|
+
# — the arguments a ransackable scope takes, which Ruby cannot report for
|
|
16
|
+
# a `scope` lambda. A scope taking none is `'boolean'`; an undeclared one
|
|
17
|
+
# is published as taking one text value.
|
|
18
|
+
class_attribute :ransackable_scope_types, default: {}
|
|
19
|
+
|
|
14
20
|
# Associations the Store API may filter through. Empty by default: every
|
|
15
21
|
# hop is a join into data the storefront was never meant to query, and a
|
|
16
22
|
# join back to the model it came from lets one filter chain them forever.
|
|
@@ -21,6 +27,9 @@ module Spree::RansackableAttributes
|
|
|
21
27
|
class_attribute :private_ransackable_attributes, default: {}
|
|
22
28
|
class_attribute :private_ransackable_scopes, default: {}
|
|
23
29
|
|
|
30
|
+
# Attributes the `search` filter matches, set with {.search_by}.
|
|
31
|
+
class_attribute :search_attributes, default: [], instance_accessor: false
|
|
32
|
+
|
|
24
33
|
class_attribute :default_ransackable_attributes
|
|
25
34
|
# `position` is included so any `acts_as_list` model is sortable by it
|
|
26
35
|
# without each subclass having to opt in. Ransack ignores attributes
|
|
@@ -48,10 +57,47 @@ module Spree::RansackableAttributes
|
|
|
48
57
|
def self.ransackable_scopes(auth_object = nil)
|
|
49
58
|
base = (whitelisted_ransackable_scopes || []).map(&:to_s)
|
|
50
59
|
base |= Spree.ransack.custom_scopes_for(self).map(&:to_s)
|
|
60
|
+
base |= %w[search] if search_attributes.any? && search_attributes.all? { |path| ransackable_path?(path, auth_object) }
|
|
51
61
|
return base unless Spree::RansackableAttributes.restricted_audience?(auth_object)
|
|
52
62
|
|
|
53
63
|
base - Array(private_ransackable_scopes[auth_object.to_sym])
|
|
54
64
|
end
|
|
65
|
+
|
|
66
|
+
# Declares the `search` filter (`q[search]=term`): a case-insensitive
|
|
67
|
+
# partial match on any of the given attributes, which may reach through
|
|
68
|
+
# associations (`variant_sku`). It runs as Ransack's `_cont` on those
|
|
69
|
+
# attributes, so translated names match in the current locale. An
|
|
70
|
+
# audience that may not filter on every one of them does not get it.
|
|
71
|
+
#
|
|
72
|
+
# search_by :name, :code
|
|
73
|
+
#
|
|
74
|
+
# @param attributes [Array<Symbol, String>]
|
|
75
|
+
def self.search_by(*attributes)
|
|
76
|
+
self.search_attributes = attributes.map(&:to_s).freeze
|
|
77
|
+
scope :search, ->(query) {
|
|
78
|
+
query.blank? ? all : ransack("#{search_attributes.join('_or_')}_cont" => query.to_s.strip).result
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Whether an attribute, or one reached through associations
|
|
83
|
+
# (`variant_product_name`), is filterable by this audience.
|
|
84
|
+
#
|
|
85
|
+
# @param path [String]
|
|
86
|
+
# @param auth_object [Symbol, nil]
|
|
87
|
+
# @return [Boolean]
|
|
88
|
+
def self.ransackable_path?(path, auth_object = nil, depth = 0)
|
|
89
|
+
return true if ransackable_attributes(auth_object).include?(path)
|
|
90
|
+
return false if depth >= 2
|
|
91
|
+
|
|
92
|
+
ransackable_associations(auth_object).any? do |name|
|
|
93
|
+
next false unless path.start_with?("#{name}_")
|
|
94
|
+
|
|
95
|
+
reflection = reflect_on_association(name.to_sym)
|
|
96
|
+
next false if reflection.nil? || reflection.polymorphic? || !reflection.klass.respond_to?(:ransackable_path?)
|
|
97
|
+
|
|
98
|
+
reflection.klass.ransackable_path?(path.delete_prefix("#{name}_"), auth_object, depth + 1)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
55
101
|
end
|
|
56
102
|
|
|
57
103
|
# @param auth_object [Symbol, nil] the Ransack auth object a search ran with
|
|
@@ -97,7 +97,7 @@ module Spree
|
|
|
97
97
|
variant_ids = items.reject(&:marked_for_destruction?).filter_map(&:variant_id)
|
|
98
98
|
return if variant_ids.uniq.size == variant_ids.size
|
|
99
99
|
|
|
100
|
-
errors.add(:items, :duplicate_variant, message:
|
|
100
|
+
errors.add(:items, :duplicate_variant, message: I18n.t('spree.errors.messages.duplicate_variant'))
|
|
101
101
|
end
|
|
102
102
|
end
|
|
103
103
|
end
|
|
@@ -25,10 +25,6 @@ module Spree
|
|
|
25
25
|
model_class.arel_table[attribute.to_sym].lower.matches("%#{escaped}%", '\\')
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
|
-
|
|
29
|
-
# Backward compatibility aliases — remove in Spree 6.0
|
|
30
|
-
def self.sanitize_query_for_multi_search(query) = sanitize_query_for_search(query)
|
|
31
|
-
def self.multi_search_condition(model_class, attribute, query) = search_condition(model_class, attribute, query)
|
|
32
28
|
end
|
|
33
29
|
end
|
|
34
30
|
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
# Stores a model's `:password` preferences in a separate `secret_preferences`
|
|
3
|
+
# text column, encrypted with Active Record encryption whenever keys are
|
|
4
|
+
# configured, so the `preferences` column never holds a secret. Declarations
|
|
5
|
+
# are unchanged: `preference :secret_key, :password` and
|
|
6
|
+
# `preferred_secret_key` read and write the encrypted column.
|
|
7
|
+
#
|
|
8
|
+
# Values written before encryption was enabled stay readable and are
|
|
9
|
+
# encrypted on the next save, or at once by
|
|
10
|
+
# `spree:upgrade:encrypt_secret_preferences`.
|
|
11
|
+
module SecretPreferences
|
|
12
|
+
extend ActiveSupport::Concern
|
|
13
|
+
|
|
14
|
+
included do
|
|
15
|
+
serialize :secret_preferences, coder: TextHashSerializer
|
|
16
|
+
|
|
17
|
+
if ActiveRecord::Encryption.config.has_primary_key?
|
|
18
|
+
encrypts :secret_preferences, support_unencrypted_data: true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
before_save :move_secret_preferences
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# The column is `text`, since ciphertext cannot live in a JSON column. An
|
|
25
|
+
# empty column stays nil rather than `{}`: encrypted attributes compare the
|
|
26
|
+
# stored value with the loaded one, so `{}` would mark every record without
|
|
27
|
+
# secrets as changed.
|
|
28
|
+
class TextHashSerializer
|
|
29
|
+
def self.dump(hash)
|
|
30
|
+
ActiveSupport::JSON.encode(hash) unless hash.nil?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.load(json)
|
|
34
|
+
Spree::Metadata::HashSerializer.load(ActiveSupport::JSON.decode(json)) unless json.nil?
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Both columns as they should be stored, when `preferences` holds a secret
|
|
39
|
+
# — one assigned as part of a whole hash, or one the upgrade has not moved
|
|
40
|
+
# yet. A secret found there is the newer value and wins.
|
|
41
|
+
#
|
|
42
|
+
# @return [Hash{Symbol => Hash}, nil] `preferences:` and `secret_preferences:`, or nil when there is nothing to move
|
|
43
|
+
def separated_secret_preferences
|
|
44
|
+
secrets = (preferences || {}).slice(*self.class.secret_preference_names)
|
|
45
|
+
return if secrets.empty?
|
|
46
|
+
|
|
47
|
+
{ preferences: preferences.except(*secrets.keys), secret_preferences: (secret_preferences || {}).merge(secrets) }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# Keeps a secret out of the plain `preferences` column when the record is
|
|
53
|
+
# saved.
|
|
54
|
+
def move_secret_preferences
|
|
55
|
+
separated = separated_secret_preferences
|
|
56
|
+
assign_attributes(separated) if separated
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
# Gives attachment slots their API write name, `<slot>_signed_id`
|
|
3
|
+
# (docs/plans/6.0-uploads-and-file-ownership.md).
|
|
4
|
+
#
|
|
5
|
+
# signed_id_attachments :logo, :mailer_logo
|
|
6
|
+
# store.update(logo_signed_id: upload.signed_id) # attaches
|
|
7
|
+
# store.update(logo_signed_id: nil) # removes
|
|
8
|
+
#
|
|
9
|
+
# A declared slot also refuses a file stored with the other visibility:
|
|
10
|
+
# attaching never moves a file between storage services, so a public upload
|
|
11
|
+
# attached to a private slot would stay readable at a public URL.
|
|
12
|
+
module SignedIdAttachments
|
|
13
|
+
extend ActiveSupport::Concern
|
|
14
|
+
|
|
15
|
+
included do
|
|
16
|
+
class_attribute :signed_id_attachment_slots, instance_writer: false, default: []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class_methods do
|
|
20
|
+
# @param slots [Array<Symbol>] `has_one_attached` slot names
|
|
21
|
+
# @return [void]
|
|
22
|
+
def signed_id_attachments(*slots)
|
|
23
|
+
validate :signed_id_attachments_on_their_storage if signed_id_attachment_slots.empty?
|
|
24
|
+
self.signed_id_attachment_slots += slots
|
|
25
|
+
|
|
26
|
+
slots.each do |slot|
|
|
27
|
+
define_method(:"#{slot}_signed_id=") { |signed_id| public_send(:"#{slot}=", signed_id) }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# The name the API reports +attribute+'s errors under: `logo_signed_id`
|
|
32
|
+
# for the `logo` slot, so a client reads them back under the field it sent.
|
|
33
|
+
#
|
|
34
|
+
# @param attribute [Symbol, String]
|
|
35
|
+
# @return [String, nil] nil when +attribute+ is not a declared slot
|
|
36
|
+
def signed_id_attribute_for(attribute)
|
|
37
|
+
"#{attribute}_signed_id" if signed_id_attachment_slots.include?(attribute.to_sym)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def signed_id_attachments_on_their_storage
|
|
44
|
+
signed_id_attachment_slots.each do |slot|
|
|
45
|
+
blob = attachment_changes[slot.to_s].try(:blob)
|
|
46
|
+
expected_service = self.class.reflect_on_attachment(slot)&.options&.dig(:service_name)
|
|
47
|
+
next if blob.nil? || expected_service.nil? || blob.service_name.to_s == expected_service.to_s
|
|
48
|
+
|
|
49
|
+
visibility = expected_service.to_s == Spree.private_storage_service_name.to_s ? 'private' : 'public'
|
|
50
|
+
errors.add(slot, :wrong_visibility, message: I18n.t('spree.upload_wrong_visibility', visibility: visibility))
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -19,7 +19,7 @@ module Spree
|
|
|
19
19
|
|
|
20
20
|
def ensure_store_association_is_not_changed
|
|
21
21
|
if store_id_changed? && persisted?
|
|
22
|
-
errors.add(:store, :store_association_can_not_be_changed, message:
|
|
22
|
+
errors.add(:store, :store_association_can_not_be_changed, message: I18n.t('spree.errors.messages.store_association_can_not_be_changed'))
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Stores
|
|
3
|
+
# The colors and font of a store's customer emails (see Spree::Emails::Branding).
|
|
4
|
+
# All optional: a blank one keeps the shipped design.
|
|
5
|
+
module EmailBranding
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
Spree::Emails::Branding::COLORS.each { |name| preference :"email_#{name}", :string, format: :color }
|
|
10
|
+
preference :email_font, :string, choices: -> { Spree::Emails::Branding::FONTS.keys }
|
|
11
|
+
|
|
12
|
+
validate :email_branding_valid
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @param overrides [Hash] unsaved values, e.g. to preview them
|
|
16
|
+
# @return [Spree::Emails::Branding]
|
|
17
|
+
def email_branding(overrides = {})
|
|
18
|
+
saved = Spree::Emails::Branding.attribute_names.to_h { |name| [name, public_send(:"preferred_email_#{name}")] }
|
|
19
|
+
Spree::Emails::Branding.new(saved.merge(overrides.to_h.stringify_keys.slice(*saved.keys)))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def email_branding_valid
|
|
25
|
+
branding = email_branding
|
|
26
|
+
return if branding.valid?
|
|
27
|
+
|
|
28
|
+
branding.errors.each { |error| errors.add(:"preferred_email_#{error.attribute}", error.type) }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -7,6 +7,9 @@ module Spree
|
|
|
7
7
|
has_many :markets, class_name: 'Spree::Market', dependent: :destroy
|
|
8
8
|
has_one :default_market, -> { default }, class_name: 'Spree::Market'
|
|
9
9
|
|
|
10
|
+
normalizes :default_locale, with: ->(value) { value.to_s.strip.presence }
|
|
11
|
+
validates_with Spree::LocaleCodesValidator, attributes: %i[default_locale supported_locales]
|
|
12
|
+
|
|
10
13
|
after_create :ensure_default_market
|
|
11
14
|
after_update :sync_default_market_settings
|
|
12
15
|
end
|
|
@@ -145,7 +148,7 @@ module Spree
|
|
|
145
148
|
markets.create!(
|
|
146
149
|
name: country.name,
|
|
147
150
|
currency: read_attribute(:default_currency) || iso_country&.currency_code || 'USD',
|
|
148
|
-
default_locale: read_attribute(:default_locale) || iso_country&.languages_official&.first || 'en',
|
|
151
|
+
default_locale: read_attribute(:default_locale) || Spree::Locales.listed(iso_country&.languages_official&.first) || 'en',
|
|
149
152
|
supported_locales: read_attribute(:supported_locales),
|
|
150
153
|
default: true,
|
|
151
154
|
bootstrap_default: true,
|
|
@@ -190,7 +193,7 @@ module Spree
|
|
|
190
193
|
end
|
|
191
194
|
|
|
192
195
|
def legacy_supported_locales_list
|
|
193
|
-
(read_attribute(:supported_locales).to_s.split(',') << default_locale).
|
|
196
|
+
(read_attribute(:supported_locales).to_s.split(',').map(&:strip) << default_locale).compact_blank.uniq.sort
|
|
194
197
|
end
|
|
195
198
|
end
|
|
196
199
|
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
# Names and describes each kind in a family of typed subclasses (promotion
|
|
3
|
+
# rules, collection rules, …) from one translation scope keyed by
|
|
4
|
+
# +api_type+, so the `/types` endpoints and dashboard pickers label
|
|
5
|
+
# extension kinds the same way as built-in ones.
|
|
6
|
+
#
|
|
7
|
+
# class Spree::PromotionRule < Spree.base_class
|
|
8
|
+
# include Spree::TypeLabels
|
|
9
|
+
# self.type_labels_scope = 'spree.promotion_rule_types'
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
# Spree::Promotion::Rules::Currency.human_name # => spree.promotion_rule_types.currency.name
|
|
13
|
+
module TypeLabels
|
|
14
|
+
extend ActiveSupport::Concern
|
|
15
|
+
|
|
16
|
+
included do
|
|
17
|
+
class_attribute :type_labels_scope, instance_writer: false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class_methods do
|
|
21
|
+
# @return [String] the kind's name, falling back to its humanized +api_type+
|
|
22
|
+
def human_name
|
|
23
|
+
I18n.t("#{type_labels_scope}.#{api_type}.name", default: api_type.titleize)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @return [String] what the kind does, empty when it has no translation
|
|
27
|
+
def human_description
|
|
28
|
+
I18n.t("#{type_labels_scope}.#{api_type}.description", default: '')
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @return [String]
|
|
33
|
+
def human_name = self.class.human_name
|
|
34
|
+
|
|
35
|
+
# @return [String]
|
|
36
|
+
def human_description = self.class.human_description
|
|
37
|
+
end
|
|
38
|
+
end
|