spree_api 6.0.0.rc1 → 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/Rakefile +0 -17
- data/app/controllers/concerns/spree/api/v3/admin/product_membership.rb +10 -0
- data/app/controllers/concerns/spree/api/v3/admin/stock_receipt_actions.rb +26 -4
- data/app/controllers/concerns/spree/api/v3/admin/subclassed_resource.rb +14 -28
- data/app/controllers/concerns/spree/api/v3/admin/validation_details.rb +1 -1
- data/app/controllers/concerns/spree/api/v3/cart_resolvable.rb +3 -2
- data/app/controllers/concerns/spree/api/v3/channel_resolution.rb +1 -1
- data/app/controllers/concerns/spree/api/v3/company_address_writes.rb +3 -1
- data/app/controllers/concerns/spree/api/v3/error_handler.rb +48 -2
- data/app/controllers/concerns/spree/api/v3/file_uploads.rb +35 -0
- data/app/controllers/concerns/spree/api/v3/money_params.rb +52 -0
- data/app/controllers/concerns/spree/api/v3/orders/claim_actions.rb +1 -5
- data/app/controllers/concerns/spree/api/v3/orders/delivery_actions.rb +6 -6
- data/app/controllers/concerns/spree/api/v3/orders/exchange_actions.rb +1 -4
- data/app/controllers/concerns/spree/api/v3/orders/fulfillment_actions.rb +1 -5
- data/app/controllers/concerns/spree/api/v3/orders/return_actions.rb +1 -4
- data/app/controllers/concerns/spree/api/v3/orders/shipping_label_actions.rb +5 -21
- data/app/controllers/concerns/spree/api/v3/params_normalizer.rb +5 -0
- data/app/controllers/concerns/spree/api/v3/purchase_serialization.rb +26 -0
- data/app/controllers/concerns/spree/api/v3/request_params.rb +65 -0
- data/app/controllers/concerns/spree/api/v3/strict_money_params.rb +94 -0
- data/app/controllers/spree/api/v3/admin/admin_users_controller.rb +10 -1
- data/app/controllers/spree/api/v3/admin/allowed_origins_controller.rb +8 -1
- data/app/controllers/spree/api/v3/admin/api_keys_controller.rb +15 -7
- data/app/controllers/spree/api/v3/admin/base_controller.rb +1 -0
- data/app/controllers/spree/api/v3/admin/catalogs/order_minimums_controller.rb +3 -1
- data/app/controllers/spree/api/v3/admin/catalogs/quantity_rules_controller.rb +7 -5
- data/app/controllers/spree/api/v3/admin/catalogs_controller.rb +60 -33
- data/app/controllers/spree/api/v3/admin/categories/products_controller.rb +4 -1
- data/app/controllers/spree/api/v3/admin/categories_controller.rb +40 -20
- data/app/controllers/spree/api/v3/admin/channels_controller.rb +39 -6
- data/app/controllers/spree/api/v3/admin/claim_reasons_controller.rb +5 -1
- data/app/controllers/spree/api/v3/admin/collections/products_controller.rb +4 -1
- data/app/controllers/spree/api/v3/admin/collections_controller.rb +44 -15
- data/app/controllers/spree/api/v3/admin/commission_rates_controller.rb +60 -12
- data/app/controllers/spree/api/v3/admin/companies/addresses_controller.rb +11 -0
- data/app/controllers/spree/api/v3/admin/companies/memberships_controller.rb +9 -1
- data/app/controllers/spree/api/v3/admin/companies/tax_exemption_certificates_controller.rb +19 -18
- data/app/controllers/spree/api/v3/admin/companies/tax_identifiers_controller.rb +6 -1
- data/app/controllers/spree/api/v3/admin/companies_controller.rb +17 -3
- data/app/controllers/spree/api/v3/admin/countries_controller.rb +5 -1
- data/app/controllers/spree/api/v3/admin/custom_field_definitions_controller.rb +21 -11
- data/app/controllers/spree/api/v3/admin/custom_fields_controller.rb +12 -5
- data/app/controllers/spree/api/v3/admin/customer_groups_controller.rb +9 -1
- data/app/controllers/spree/api/v3/admin/customers/addresses_controller.rb +12 -7
- data/app/controllers/spree/api/v3/admin/customers/store_credits_controller.rb +11 -9
- data/app/controllers/spree/api/v3/admin/customers/tax_identifiers_controller.rb +6 -1
- data/app/controllers/spree/api/v3/admin/customers_controller.rb +35 -7
- data/app/controllers/spree/api/v3/admin/data_requests_controller.rb +8 -0
- data/app/controllers/spree/api/v3/admin/delivery_method_rules_controller.rb +1 -1
- data/app/controllers/spree/api/v3/admin/delivery_methods/rules_controller.rb +15 -7
- data/app/controllers/spree/api/v3/admin/delivery_methods_controller.rb +92 -57
- data/app/controllers/spree/api/v3/admin/delivery_profiles/origin_groups_controller.rb +8 -1
- data/app/controllers/spree/api/v3/admin/delivery_profiles_controller.rb +13 -1
- data/app/controllers/spree/api/v3/admin/delivery_zones_controller.rb +21 -5
- data/app/controllers/spree/api/v3/admin/email_templates/drafts_controller.rb +14 -1
- data/app/controllers/spree/api/v3/admin/email_templates/previews_controller.rb +4 -0
- data/app/controllers/spree/api/v3/admin/email_templates/publications_controller.rb +7 -0
- data/app/controllers/spree/api/v3/admin/email_templates/restorations_controller.rb +8 -0
- data/app/controllers/spree/api/v3/admin/email_templates/test_emails_controller.rb +4 -0
- data/app/controllers/spree/api/v3/admin/exports_controller.rb +23 -6
- data/app/controllers/spree/api/v3/admin/files_controller.rb +29 -0
- data/app/controllers/spree/api/v3/admin/gift_card_batches_controller.rb +20 -1
- data/app/controllers/spree/api/v3/admin/gift_cards_controller.rb +19 -1
- data/app/controllers/spree/api/v3/admin/imports_controller.rb +36 -9
- data/app/controllers/spree/api/v3/admin/integrations_controller.rb +13 -1
- data/app/controllers/spree/api/v3/admin/invitation_acceptances_controller.rb +9 -2
- data/app/controllers/spree/api/v3/admin/invitations_controller.rb +8 -1
- data/app/controllers/spree/api/v3/admin/locales_controller.rb +1 -1
- data/app/controllers/spree/api/v3/admin/markets_controller.rb +30 -9
- data/app/controllers/spree/api/v3/admin/me_controller.rb +12 -3
- data/app/controllers/spree/api/v3/admin/media_controller.rb +22 -9
- data/app/controllers/spree/api/v3/admin/media_library_controller.rb +4 -0
- data/app/controllers/spree/api/v3/admin/option_types_controller.rb +24 -7
- data/app/controllers/spree/api/v3/admin/order_cancellation_reasons_controller.rb +5 -1
- data/app/controllers/spree/api/v3/admin/order_routing_rules_controller.rb +13 -1
- data/app/controllers/spree/api/v3/admin/orders/claims_controller.rb +39 -1
- data/app/controllers/spree/api/v3/admin/orders/deliveries_controller.rb +19 -1
- data/app/controllers/spree/api/v3/admin/orders/discount_codes_controller.rb +5 -1
- data/app/controllers/spree/api/v3/admin/orders/discounts_controller.rb +29 -5
- data/app/controllers/spree/api/v3/admin/orders/exchanges_controller.rb +36 -1
- data/app/controllers/spree/api/v3/admin/orders/fees_controller.rb +22 -1
- data/app/controllers/spree/api/v3/admin/orders/fulfillments_controller.rb +66 -7
- data/app/controllers/spree/api/v3/admin/orders/gift_cards_controller.rb +6 -2
- data/app/controllers/spree/api/v3/admin/orders/items_controller.rb +11 -1
- data/app/controllers/spree/api/v3/admin/orders/labels_controller.rb +35 -2
- data/app/controllers/spree/api/v3/admin/orders/payments_controller.rb +16 -5
- data/app/controllers/spree/api/v3/admin/orders/refunds_controller.rb +6 -0
- data/app/controllers/spree/api/v3/admin/orders/returns_controller.rb +37 -1
- data/app/controllers/spree/api/v3/admin/orders/store_credits_controller.rb +6 -3
- data/app/controllers/spree/api/v3/admin/orders_controller.rb +74 -60
- data/app/controllers/spree/api/v3/admin/package_types_controller.rb +30 -5
- data/app/controllers/spree/api/v3/admin/password_resets_controller.rb +17 -0
- data/app/controllers/spree/api/v3/admin/payment_methods_controller.rb +38 -22
- data/app/controllers/spree/api/v3/admin/policies_controller.rb +8 -4
- data/app/controllers/spree/api/v3/admin/price_lists_controller.rb +27 -15
- data/app/controllers/spree/api/v3/admin/prices_controller.rb +51 -4
- data/app/controllers/spree/api/v3/admin/product_types_controller.rb +25 -8
- data/app/controllers/spree/api/v3/admin/products/digital_assets_controller.rb +27 -10
- data/app/controllers/spree/api/v3/admin/products/variants_controller.rb +9 -14
- data/app/controllers/spree/api/v3/admin/products_controller.rb +121 -70
- data/app/controllers/spree/api/v3/admin/promotion_actions_controller.rb +11 -2
- data/app/controllers/spree/api/v3/admin/promotion_rules_controller.rb +10 -1
- data/app/controllers/spree/api/v3/admin/promotions_controller.rb +50 -14
- data/app/controllers/spree/api/v3/admin/purchase_orders_controller.rb +54 -7
- data/app/controllers/spree/api/v3/admin/refund_reasons_controller.rb +5 -1
- data/app/controllers/spree/api/v3/admin/reporting/saved_reports_controller.rb +9 -1
- data/app/controllers/spree/api/v3/admin/reporting_controller.rb +34 -0
- data/app/controllers/spree/api/v3/admin/resource_controller.rb +1 -0
- data/app/controllers/spree/api/v3/admin/return_reasons_controller.rb +5 -1
- data/app/controllers/spree/api/v3/admin/roles_controller.rb +13 -1
- data/app/controllers/spree/api/v3/admin/seller_payouts_controller.rb +6 -0
- data/app/controllers/spree/api/v3/admin/seller_requirement_submissions_controller.rb +15 -0
- data/app/controllers/spree/api/v3/admin/seller_requirements_controller.rb +32 -6
- data/app/controllers/spree/api/v3/admin/sellers_controller.rb +75 -22
- data/app/controllers/spree/api/v3/admin/setup_controller.rb +54 -15
- data/app/controllers/spree/api/v3/admin/stock_levels_controller.rb +38 -9
- data/app/controllers/spree/api/v3/admin/stock_locations_controller.rb +41 -9
- data/app/controllers/spree/api/v3/admin/stock_transfers_controller.rb +48 -7
- data/app/controllers/spree/api/v3/admin/store_controller.rb +122 -53
- data/app/controllers/spree/api/v3/admin/store_credits_controller.rb +1 -7
- data/app/controllers/spree/api/v3/admin/suppliers_controller.rb +16 -6
- data/app/controllers/spree/api/v3/admin/tax_categories_controller.rb +7 -4
- data/app/controllers/spree/api/v3/admin/tax_rates_controller.rb +21 -3
- data/app/controllers/spree/api/v3/admin/tracking_carriers_controller.rb +4 -0
- data/app/controllers/spree/api/v3/admin/translations/batches_controller.rb +17 -9
- data/app/controllers/spree/api/v3/admin/translations_controller.rb +4 -0
- data/app/controllers/spree/api/v3/admin/translations_coverage_controller.rb +5 -0
- data/app/controllers/spree/api/v3/admin/updates_controller.rb +39 -0
- data/app/controllers/spree/api/v3/admin/webhook_endpoints_controller.rb +23 -1
- data/app/controllers/spree/api/v3/base_controller.rb +2 -0
- data/app/controllers/spree/api/v3/resource_controller.rb +63 -10
- data/app/controllers/spree/api/v3/seller/auth_controller.rb +8 -0
- data/app/controllers/spree/api/v3/seller/base_controller.rb +1 -0
- data/app/controllers/spree/api/v3/seller/countries_controller.rb +2 -2
- data/app/controllers/spree/api/v3/seller/delivery_methods_controller.rb +49 -60
- data/app/controllers/spree/api/v3/seller/exports_controller.rb +18 -1
- data/app/controllers/spree/api/v3/seller/files_controller.rb +27 -0
- data/app/controllers/spree/api/v3/seller/imports_controller.rb +25 -9
- data/app/controllers/spree/api/v3/seller/invitation_acceptances_controller.rb +9 -1
- data/app/controllers/spree/api/v3/seller/me_controller.rb +14 -3
- data/app/controllers/spree/api/v3/seller/onboarding_controller.rb +11 -0
- data/app/controllers/spree/api/v3/seller/orders/claims_controller.rb +35 -0
- data/app/controllers/spree/api/v3/seller/orders/deliveries_controller.rb +12 -0
- data/app/controllers/spree/api/v3/seller/orders/exchanges_controller.rb +33 -0
- data/app/controllers/spree/api/v3/seller/orders/fulfillments_controller.rb +28 -2
- data/app/controllers/spree/api/v3/seller/orders/labels_controller.rb +22 -1
- data/app/controllers/spree/api/v3/seller/orders/notes_controller.rb +8 -1
- data/app/controllers/spree/api/v3/seller/orders/returns_controller.rb +32 -0
- data/app/controllers/spree/api/v3/seller/orders_controller.rb +35 -14
- data/app/controllers/spree/api/v3/seller/package_types_controller.rb +21 -9
- data/app/controllers/spree/api/v3/seller/password_resets_controller.rb +10 -0
- data/app/controllers/spree/api/v3/seller/policies_controller.rb +12 -4
- data/app/controllers/spree/api/v3/seller/products_controller.rb +114 -28
- data/app/controllers/spree/api/v3/seller/profile_controller.rb +33 -10
- data/app/controllers/spree/api/v3/seller/requirement_submissions_controller.rb +12 -5
- data/app/controllers/spree/api/v3/seller/resource_controller.rb +12 -0
- data/app/controllers/spree/api/v3/seller/stock_locations_controller.rb +44 -13
- data/app/controllers/spree/api/v3/seller/tax_identifiers_controller.rb +10 -1
- data/app/controllers/spree/api/v3/seller/team_controller.rb +4 -0
- data/app/controllers/spree/api/v3/store/auth_controller.rb +10 -0
- data/app/controllers/spree/api/v3/store/carts/discount_codes_controller.rb +8 -1
- data/app/controllers/spree/api/v3/store/carts/fulfillments_controller.rb +10 -2
- data/app/controllers/spree/api/v3/store/carts/gift_cards_controller.rb +8 -1
- data/app/controllers/spree/api/v3/store/carts/items_controller.rb +17 -5
- data/app/controllers/spree/api/v3/store/carts/payment_sessions_controller.rb +20 -6
- data/app/controllers/spree/api/v3/store/carts/payments_controller.rb +11 -0
- data/app/controllers/spree/api/v3/store/carts/po_documents_controller.rb +24 -26
- data/app/controllers/spree/api/v3/store/carts/store_credits_controller.rb +7 -1
- data/app/controllers/spree/api/v3/store/carts/tax_identifiers_controller.rb +5 -1
- data/app/controllers/spree/api/v3/store/carts_controller.rb +56 -47
- data/app/controllers/spree/api/v3/store/companies/addresses_controller.rb +12 -4
- data/app/controllers/spree/api/v3/store/companies/members_controller.rb +4 -0
- data/app/controllers/spree/api/v3/store/companies_controller.rb +5 -1
- data/app/controllers/spree/api/v3/store/company_invitations_controller.rb +9 -1
- data/app/controllers/spree/api/v3/store/customer/addresses_controller.rb +8 -7
- data/app/controllers/spree/api/v3/store/customer/data_requests_controller.rb +5 -0
- data/app/controllers/spree/api/v3/store/customer/password_resets_controller.rb +17 -0
- data/app/controllers/spree/api/v3/store/customer/payment_setup_sessions_controller.rb +10 -5
- data/app/controllers/spree/api/v3/store/customer/tax_identifiers_controller.rb +5 -1
- data/app/controllers/spree/api/v3/store/customers_controller.rb +28 -2
- data/app/controllers/spree/api/v3/store/newsletter_subscribers_controller.rb +22 -0
- data/app/controllers/spree/api/v3/store/orders/claims_controller.rb +11 -2
- data/app/controllers/spree/api/v3/store/orders/returns_controller.rb +10 -1
- data/app/controllers/spree/api/v3/store/orders_controller.rb +47 -10
- data/app/controllers/spree/api/v3/store/products_controller.rb +8 -0
- data/app/controllers/spree/api/v3/store/wishlist_items_controller.rb +10 -4
- data/app/controllers/spree/api/v3/store/wishlists_controller.rb +12 -4
- data/app/request_schemas/spree/api/v3/address_request_schema.rb +27 -0
- data/app/request_schemas/spree/api/v3/admin/address_request_schema.rb +13 -0
- data/app/request_schemas/spree/api/v3/admin/bulk_tags_request_schema.rb +17 -0
- data/app/request_schemas/spree/api/v3/admin/catalog_order_minimum_request_schema.rb +17 -0
- data/app/request_schemas/spree/api/v3/admin/email_template_language_request_schema.rb +17 -0
- data/app/request_schemas/spree/api/v3/admin/email_template_preview_request_schema.rb +32 -0
- data/app/request_schemas/spree/api/v3/admin/price_adjustment_tier_request_schema.rb +21 -0
- data/app/request_schemas/spree/api/v3/admin/price_list_price_request_schema.rb +21 -0
- data/app/request_schemas/spree/api/v3/admin/price_list_rule_request_schema.rb +19 -0
- data/app/request_schemas/spree/api/v3/admin/product_membership_reposition_request_schema.rb +17 -0
- data/app/request_schemas/spree/api/v3/admin/promotion_action_calculator_request_schema.rb +18 -0
- data/app/request_schemas/spree/api/v3/admin/promotion_action_line_item_request_schema.rb +15 -0
- data/app/request_schemas/spree/api/v3/admin/promotion_action_request_schema.rb +19 -0
- data/app/request_schemas/spree/api/v3/admin/promotion_rule_request_schema.rb +22 -0
- data/app/request_schemas/spree/api/v3/admin/reason_request_schema.rb +14 -0
- data/app/request_schemas/spree/api/v3/admin/tax_identifier_request_schema.rb +15 -0
- data/app/request_schemas/spree/api/v3/custom_field_value_request_schema.rb +15 -0
- data/app/request_schemas/spree/api/v3/file_upload_request_schema.rb +20 -0
- data/app/request_schemas/spree/api/v3/media_request_schema.rb +27 -0
- data/app/request_schemas/spree/api/v3/price_request_schema.rb +17 -0
- data/app/request_schemas/spree/api/v3/stock_level_request_schema.rb +18 -0
- data/app/request_schemas/spree/api/v3/store/address_request_schema.rb +29 -0
- data/app/request_schemas/spree/api/v3/tax_identifier_request_schema.rb +18 -0
- data/app/request_schemas/spree/api/v3/variant_option_request_schema.rb +13 -0
- data/app/request_schemas/spree/api/v3/variant_request_schema.rb +52 -0
- data/app/serializers/concerns/spree/api/v3/purchase_summary.rb +48 -0
- data/app/serializers/spree/api/v3/address_serializer.rb +4 -2
- data/app/serializers/spree/api/v3/admin/address_serializer.rb +3 -0
- data/app/serializers/spree/api/v3/admin/applied_promotion_serializer.rb +3 -1
- data/app/serializers/spree/api/v3/admin/cart_serializer.rb +3 -1
- data/app/serializers/spree/api/v3/admin/catalog_order_minimum_serializer.rb +3 -2
- data/app/serializers/spree/api/v3/admin/catalog_price_serializer.rb +3 -4
- data/app/serializers/spree/api/v3/admin/catalog_price_tier_serializer.rb +4 -3
- data/app/serializers/spree/api/v3/admin/channel_serializer.rb +5 -7
- data/app/serializers/spree/api/v3/admin/claim_line_item_serializer.rb +7 -0
- data/app/serializers/spree/api/v3/admin/claim_serializer.rb +5 -0
- data/app/serializers/spree/api/v3/admin/commission_line_serializer.rb +7 -18
- data/app/serializers/spree/api/v3/admin/commission_rate_serializer.rb +7 -11
- data/app/serializers/spree/api/v3/admin/commission_rule_serializer.rb +0 -2
- data/app/serializers/spree/api/v3/admin/country_serializer.rb +4 -0
- data/app/serializers/spree/api/v3/admin/customer_serializer.rb +3 -7
- data/app/serializers/spree/api/v3/admin/delivery_method_rule_serializer.rb +0 -2
- data/app/serializers/spree/api/v3/admin/delivery_method_serializer.rb +14 -10
- data/app/serializers/spree/api/v3/admin/delivery_method_service_serializer.rb +9 -1
- data/app/serializers/spree/api/v3/admin/delivery_rate_serializer.rb +8 -0
- data/app/serializers/spree/api/v3/admin/discount_serializer.rb +3 -1
- data/app/serializers/spree/api/v3/admin/exchange_line_item_serializer.rb +5 -0
- data/app/serializers/spree/api/v3/admin/exchange_serializer.rb +5 -0
- data/app/serializers/spree/api/v3/admin/fee_serializer.rb +3 -1
- data/app/serializers/spree/api/v3/admin/file_upload_serializer.rb +11 -0
- data/app/serializers/spree/api/v3/admin/file_upload_target_serializer.rb +10 -0
- data/app/serializers/spree/api/v3/admin/fulfillment_serializer.rb +13 -11
- data/app/serializers/spree/api/v3/admin/gift_card_serializer.rb +3 -3
- data/app/serializers/spree/api/v3/admin/import_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/admin/integration_serializer.rb +1 -3
- data/app/serializers/spree/api/v3/admin/line_item_serializer.rb +12 -12
- data/app/serializers/spree/api/v3/admin/locale_serializer.rb +13 -0
- data/app/serializers/spree/api/v3/admin/market_serializer.rb +3 -0
- data/app/serializers/spree/api/v3/admin/media_serializer.rb +3 -2
- data/app/serializers/spree/api/v3/admin/order_group_serializer.rb +2 -0
- data/app/serializers/spree/api/v3/admin/order_routing_rule_serializer.rb +1 -3
- data/app/serializers/spree/api/v3/admin/order_serializer.rb +33 -33
- data/app/serializers/spree/api/v3/admin/payment_method_serializer.rb +1 -4
- data/app/serializers/spree/api/v3/admin/payment_serializer.rb +6 -3
- data/app/serializers/spree/api/v3/admin/payment_split_serializer.rb +8 -9
- data/app/serializers/spree/api/v3/admin/price_adjustment_tier_serializer.rb +3 -6
- data/app/serializers/spree/api/v3/admin/price_history_serializer.rb +5 -2
- data/app/serializers/spree/api/v3/admin/price_list_serializer.rb +1 -5
- data/app/serializers/spree/api/v3/admin/price_rule_serializer.rb +1 -3
- data/app/serializers/spree/api/v3/admin/price_serializer.rb +2 -0
- data/app/serializers/spree/api/v3/admin/product_serializer.rb +2 -0
- data/app/serializers/spree/api/v3/admin/promotion_action_serializer.rb +4 -6
- data/app/serializers/spree/api/v3/admin/promotion_rule_serializer.rb +0 -2
- data/app/serializers/spree/api/v3/admin/purchase_order_item_serializer.rb +5 -11
- data/app/serializers/spree/api/v3/admin/purchase_order_serializer.rb +4 -4
- data/app/serializers/spree/api/v3/admin/refund_serializer.rb +7 -3
- data/app/serializers/spree/api/v3/admin/reporting_result_serializer.rb +9 -2
- data/app/serializers/spree/api/v3/admin/return_line_item_serializer.rb +8 -0
- data/app/serializers/spree/api/v3/admin/return_serializer.rb +8 -4
- data/app/serializers/spree/api/v3/admin/seller_balance_serializer.rb +15 -10
- data/app/serializers/spree/api/v3/admin/seller_payout_serializer.rb +3 -5
- data/app/serializers/spree/api/v3/admin/seller_serializer.rb +3 -1
- data/app/serializers/spree/api/v3/admin/seller_transfer_serializer.rb +7 -8
- data/app/serializers/spree/api/v3/admin/shipping_label_serializer.rb +4 -4
- data/app/serializers/spree/api/v3/admin/stock_location_serializer.rb +3 -0
- data/app/serializers/spree/api/v3/admin/stock_movement_serializer.rb +2 -6
- data/app/serializers/spree/api/v3/admin/store_credit_event_serializer.rb +5 -0
- data/app/serializers/spree/api/v3/admin/store_credit_serializer.rb +9 -4
- data/app/serializers/spree/api/v3/admin/store_serializer.rb +17 -98
- data/app/serializers/spree/api/v3/admin/supplier_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/tax_exemption_certificate_serializer.rb +3 -1
- data/app/serializers/spree/api/v3/admin/tax_line_serializer.rb +4 -2
- data/app/serializers/spree/api/v3/admin/tax_rate_serializer.rb +2 -12
- data/app/serializers/spree/api/v3/admin/update_status_serializer.rb +28 -0
- data/app/serializers/spree/api/v3/admin/variant_serializer.rb +7 -3
- data/app/serializers/spree/api/v3/base_serializer.rb +112 -7
- data/app/serializers/spree/api/v3/cart_serializer.rb +11 -29
- data/app/serializers/spree/api/v3/claim_line_item_serializer.rb +5 -13
- data/app/serializers/spree/api/v3/claim_serializer.rb +2 -3
- data/app/serializers/spree/api/v3/country_serializer.rb +2 -1
- data/app/serializers/spree/api/v3/currency_serializer.rb +9 -1
- data/app/serializers/spree/api/v3/customer_serializer.rb +3 -2
- data/app/serializers/spree/api/v3/delivery_rate_serializer.rb +8 -12
- data/app/serializers/spree/api/v3/delivery_zone_member_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/discount_serializer.rb +4 -1
- data/app/serializers/spree/api/v3/exchange_line_item_serializer.rb +2 -8
- data/app/serializers/spree/api/v3/exchange_serializer.rb +2 -3
- data/app/serializers/spree/api/v3/file_upload_serializer.rb +28 -0
- data/app/serializers/spree/api/v3/file_upload_target_serializer.rb +17 -0
- data/app/serializers/spree/api/v3/gift_card_batch_serializer.rb +2 -4
- data/app/serializers/spree/api/v3/gift_card_serializer.rb +4 -2
- data/app/serializers/spree/api/v3/import_serializer.rb +0 -12
- data/app/serializers/spree/api/v3/line_item_serializer.rb +15 -5
- data/app/serializers/spree/api/v3/locale_serializer.rb +3 -1
- data/app/serializers/spree/api/v3/market_serializer.rb +5 -5
- data/app/serializers/spree/api/v3/media_serializer.rb +7 -2
- data/app/serializers/spree/api/v3/order_group_serializer.rb +12 -4
- data/app/serializers/spree/api/v3/order_serializer.rb +5 -23
- data/app/serializers/spree/api/v3/payment_session_serializer.rb +2 -4
- data/app/serializers/spree/api/v3/price_history_serializer.rb +5 -5
- data/app/serializers/spree/api/v3/price_serializer.rb +6 -9
- data/app/serializers/spree/api/v3/product_filter_price_range_serializer.rb +10 -4
- data/app/serializers/spree/api/v3/product_serializer.rb +3 -3
- data/app/serializers/spree/api/v3/refund_serializer.rb +8 -5
- data/app/serializers/spree/api/v3/return_line_item_serializer.rb +3 -11
- data/app/serializers/spree/api/v3/return_serializer.rb +3 -6
- data/app/serializers/spree/api/v3/seller/address_serializer.rb +12 -0
- data/app/serializers/spree/api/v3/seller/balance_serializer.rb +15 -10
- data/app/serializers/spree/api/v3/seller/claim_line_item_serializer.rb +7 -0
- data/app/serializers/spree/api/v3/seller/claim_serializer.rb +5 -0
- data/app/serializers/spree/api/v3/seller/country_serializer.rb +19 -0
- data/app/serializers/spree/api/v3/seller/delivery_method_rule_serializer.rb +1 -3
- data/app/serializers/spree/api/v3/seller/delivery_method_serializer.rb +4 -8
- data/app/serializers/spree/api/v3/seller/delivery_rate_serializer.rb +9 -8
- data/app/serializers/spree/api/v3/seller/exchange_line_item_serializer.rb +5 -0
- data/app/serializers/spree/api/v3/seller/exchange_serializer.rb +5 -0
- data/app/serializers/spree/api/v3/seller/file_upload_serializer.rb +11 -0
- data/app/serializers/spree/api/v3/seller/file_upload_target_serializer.rb +10 -0
- data/app/serializers/spree/api/v3/seller/import_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/seller/media_serializer.rb +2 -5
- data/app/serializers/spree/api/v3/seller/order_line_item_serializer.rb +4 -3
- data/app/serializers/spree/api/v3/seller/order_serializer.rb +16 -16
- data/app/serializers/spree/api/v3/seller/payment_split_serializer.rb +8 -9
- data/app/serializers/spree/api/v3/seller/payout_serializer.rb +2 -4
- data/app/serializers/spree/api/v3/seller/price_history_serializer.rb +11 -0
- data/app/serializers/spree/api/v3/seller/price_serializer.rb +11 -0
- data/app/serializers/spree/api/v3/seller/product_serializer.rb +2 -0
- data/app/serializers/spree/api/v3/seller/profile_serializer.rb +7 -7
- data/app/serializers/spree/api/v3/seller/return_line_item_serializer.rb +8 -0
- data/app/serializers/spree/api/v3/seller/return_serializer.rb +8 -5
- data/app/serializers/spree/api/v3/seller/state_serializer.rb +10 -0
- data/app/serializers/spree/api/v3/seller/stock_location_serializer.rb +3 -0
- data/app/serializers/spree/api/v3/seller/transfer_serializer.rb +6 -7
- data/app/serializers/spree/api/v3/seller/variant_serializer.rb +8 -4
- data/app/serializers/spree/api/v3/stock_location_serializer.rb +8 -1
- data/app/serializers/spree/api/v3/store_credit_event_serializer.rb +1 -3
- data/app/serializers/spree/api/v3/store_credit_serializer.rb +3 -5
- data/app/serializers/spree/api/v3/tax_line_serializer.rb +2 -4
- data/app/serializers/spree/api/v3/variant_serializer.rb +3 -3
- data/app/services/spree/api/v3/filter_predicates.rb +29 -0
- data/app/services/spree/api/v3/filter_table.rb +337 -0
- data/app/services/spree/api/v3/filters_aggregator.rb +2 -2
- data/app/services/spree/api/v3/request_schema.rb +430 -0
- data/app/services/spree/webhooks/deliver_webhook.rb +7 -3
- data/config/initializers/typelizer.rb +1 -1
- data/config/routes.rb +5 -3
- data/lib/spree/api/configuration.rb +5 -0
- data/lib/spree/api/dependencies.rb +7 -6
- data/lib/spree/api/middleware/request_size_limit.rb +24 -3
- data/lib/spree/api/openapi/filter_documentation.rb +136 -0
- data/lib/spree/api/openapi/schema_helper.rb +126 -80
- data/lib/spree/api/preference_families.rb +46 -0
- data/lib/spree/api/preference_types.rb +138 -0
- data/lib/spree/api/typelizer_generation.rb +4 -0
- data/lib/tasks/filters.rake +12 -0
- data/lib/typelizer/open_enums.rb +10 -0
- metadata +60 -10
- data/app/controllers/concerns/spree/api/v3/address_params.rb +0 -17
- data/app/controllers/concerns/spree/api/v3/direct_uploads.rb +0 -35
- data/app/controllers/spree/api/v3/admin/direct_uploads_controller.rb +0 -54
- data/app/controllers/spree/api/v3/seller/direct_uploads_controller.rb +0 -21
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module OpenAPI
|
|
4
|
+
# Turns one list endpoint's filter table into what a reader of the API
|
|
5
|
+
# reference sees: `q[search]` and the other scopes as named query
|
|
6
|
+
# parameters, and the attribute filters as a table rendered above the
|
|
7
|
+
# endpoint (Mintlify's `x-mint.content`).
|
|
8
|
+
class FilterDocumentation
|
|
9
|
+
KIND_LABELS = {
|
|
10
|
+
'text' => 'Text', 'decimal' => 'Amount', 'integer' => 'Number', 'date' => 'Date',
|
|
11
|
+
'datetime' => 'Date and time', 'id' => 'Prefixed ID', 'type' => 'Type', 'boolean' => 'True or false'
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
SCOPE_SCHEMAS = {
|
|
15
|
+
'boolean' => { type: :boolean }, 'integer' => { type: :integer }, 'decimal' => { type: :number }
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
# Raised when an endpoint offers `q[search]` and nothing says what it matches.
|
|
19
|
+
class MissingSearchDescription < StandardError; end
|
|
20
|
+
|
|
21
|
+
# @param endpoint [Spree::Api::V3::FilterTable::Endpoint]
|
|
22
|
+
# @param querying_path [String] the docs page explaining predicates
|
|
23
|
+
# @param search [String, nil] what `q[search]` matches, for a model
|
|
24
|
+
# whose search is not declared with `search_by`
|
|
25
|
+
# @param scopes [Hash{String => String}] descriptions for other scopes
|
|
26
|
+
def initialize(endpoint, querying_path:, search: nil, scopes: {})
|
|
27
|
+
@endpoint = endpoint
|
|
28
|
+
@table = endpoint.table
|
|
29
|
+
@querying_path = querying_path
|
|
30
|
+
@search = search
|
|
31
|
+
@scopes = scopes.stringify_keys
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @return [Array<Hash>] rswag parameter definitions, `q[search]` first
|
|
35
|
+
def parameters
|
|
36
|
+
names = @table.scopes.keys.sort_by { |scope| scope == 'search' ? '' : scope }
|
|
37
|
+
names.map { |scope| scope_parameter(scope, @table.scopes[scope]) }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @return [String] MDX for the endpoint page
|
|
41
|
+
def content
|
|
42
|
+
lines = ['## Filters', '']
|
|
43
|
+
lines << "Filter with `q[<attribute>_<predicate>]=value`, for example `#{example_key}`. Send a list as " \
|
|
44
|
+
"`q[<attribute>_in][]=a&q[<attribute>_in][]=b`. [How filters work](#{@querying_path})."
|
|
45
|
+
lines << ''
|
|
46
|
+
lines.concat(attribute_rows(@table))
|
|
47
|
+
|
|
48
|
+
associations = association_rows
|
|
49
|
+
if associations.any?
|
|
50
|
+
lines << '' << '<Accordion title="Filters through associations">' << ''
|
|
51
|
+
lines << 'Prefix an associated record\'s attribute with the association, as in ' \
|
|
52
|
+
"`q[#{associations.first[0]}id_eq]`. The same predicates apply." << ''
|
|
53
|
+
lines << '| Prefix | Attributes |' << '|---|---|'
|
|
54
|
+
associations.each { |prefix, attributes| lines << "| `#{prefix}` | #{attributes.map { |name| "`#{name}`" }.join(', ')} |" }
|
|
55
|
+
lines << '' << '</Accordion>'
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if @endpoint.to_h['custom_fields']
|
|
59
|
+
lines << '' << "Also filters and sorts on the store's searchable custom fields, as " \
|
|
60
|
+
'`q[cf_<namespace>_<key>_<predicate>]` and `sort=cf_<namespace>_<key>`.'
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
sortable = @endpoint.sortable - @table.aliased_attributes
|
|
64
|
+
if sortable.any?
|
|
65
|
+
lines << '' << "**Sort by:** #{sortable.map { |field| "`#{field}`" }.join(', ')}. " \
|
|
66
|
+
'Prefix a field with `-` to sort descending.'
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
lines.join("\n")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def scope_parameter(scope, type)
|
|
75
|
+
list = type.is_a?(Hash) || type.is_a?(Array)
|
|
76
|
+
{
|
|
77
|
+
name: list ? "q[#{scope}][]" : "q[#{scope}]",
|
|
78
|
+
in: :query,
|
|
79
|
+
required: false,
|
|
80
|
+
schema: scope_schema(type),
|
|
81
|
+
description: scope == 'search' ? search_description : @scopes.fetch(scope) { default_scope_description(scope, type) }
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def scope_schema(type)
|
|
86
|
+
case type
|
|
87
|
+
when Hash then { type: :array, items: scope_schema(type['list']) }
|
|
88
|
+
when Array then { type: :array, items: scope_schema(type.first), minItems: type.size, maxItems: type.size }
|
|
89
|
+
else SCOPE_SCHEMAS.fetch(type, { type: :string })
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def search_description
|
|
94
|
+
return @search if @search
|
|
95
|
+
|
|
96
|
+
attributes = @table.model.search_attributes
|
|
97
|
+
raise MissingSearchDescription, "#{@table.model.name}.search has no description; pass `search:` to filter_parameters_for" if attributes.empty?
|
|
98
|
+
|
|
99
|
+
"Matches any of #{attributes.map { |path| path.tr('_', ' ') }.to_sentence} (partial, case-insensitive)."
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def default_scope_description(scope, type)
|
|
103
|
+
type == 'boolean' ? "Set to `true` to apply `#{scope}`." : "Applies `#{scope}` to the given value."
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def attribute_rows(table)
|
|
107
|
+
rows = ['| Attribute | Kind | Predicates |', '|---|---|---|']
|
|
108
|
+
table.attributes.except(*table.aliased_attributes).each do |attribute, kind|
|
|
109
|
+
label = kind.is_a?(Hash) ? "One of #{kind['enum'].map { |value| "`#{value}`" }.join(', ')}" : KIND_LABELS.fetch(kind)
|
|
110
|
+
predicates = Spree::Api::V3::FilterPredicates::BY_KIND.fetch(kind.is_a?(Hash) ? 'enum' : kind)
|
|
111
|
+
rows << "| `#{attribute}` | #{label} | #{predicates.map { |predicate| "`#{predicate}`" }.join(' ')} |"
|
|
112
|
+
end
|
|
113
|
+
rows
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def association_rows
|
|
117
|
+
visible = ->(table) { table.attributes.keys - table.aliased_attributes }
|
|
118
|
+
@table.associations.flat_map do |name, associated|
|
|
119
|
+
nested = associated.associations.reject { |_, table| table.model == @table.model }
|
|
120
|
+
[["#{name}_", visible.(associated)]] + nested.map { |hop, table| ["#{name}_#{hop}_", visible.(table)] }
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def example_key
|
|
125
|
+
texts = @table.attributes.select { |_, value| value == 'text' }
|
|
126
|
+
attribute = (%w[number name code email] & texts.keys).first || texts.keys.first
|
|
127
|
+
kind = 'text' if attribute
|
|
128
|
+
attribute, kind = @table.attributes.first if attribute.nil?
|
|
129
|
+
return 'q[id_eq]=…' if attribute.nil?
|
|
130
|
+
|
|
131
|
+
kind == 'text' ? "q[#{attribute}_cont]=…" : "q[#{attribute}_eq]=…"
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'spree/api/preference_families'
|
|
4
|
+
|
|
3
5
|
module Spree
|
|
4
6
|
module Api
|
|
5
7
|
module OpenAPI
|
|
@@ -33,6 +35,29 @@ module Spree
|
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
# Common schemas that are not from serializers
|
|
38
|
+
# The nested calculator of a promotion action and a delivery method,
|
|
39
|
+
# keyed by the preference family its `preferences` belong to.
|
|
40
|
+
CALCULATOR_SCHEMAS = {
|
|
41
|
+
'PromotionCalculator' => [:PromotionActionCalculator, {
|
|
42
|
+
type: :object,
|
|
43
|
+
description: "The action's nested calculator (when the action carries one — null for actions like `free_shipping`)",
|
|
44
|
+
properties: {
|
|
45
|
+
type: { type: :string, example: 'flat_rate', description: 'Wire shorthand for the calculator subclass' },
|
|
46
|
+
preferences: { '$ref' => '#/components/schemas/PromotionCalculatorPreferences' }
|
|
47
|
+
},
|
|
48
|
+
required: %w[type preferences]
|
|
49
|
+
}],
|
|
50
|
+
'DeliveryCalculator' => [:DeliveryMethodCalculator, {
|
|
51
|
+
type: :object,
|
|
52
|
+
description: 'How the delivery method prices a shipment',
|
|
53
|
+
properties: {
|
|
54
|
+
type: { type: :string, example: 'flat_rate', description: 'Wire shorthand for the calculator subclass' },
|
|
55
|
+
preferences: { '$ref' => '#/components/schemas/DeliveryCalculatorPreferences' }
|
|
56
|
+
},
|
|
57
|
+
required: %w[type preferences]
|
|
58
|
+
}]
|
|
59
|
+
}.freeze
|
|
60
|
+
|
|
36
61
|
def common_schemas
|
|
37
62
|
{
|
|
38
63
|
PaginationMeta: {
|
|
@@ -162,26 +187,13 @@ module Spree
|
|
|
162
187
|
},
|
|
163
188
|
required: %w[id name code]
|
|
164
189
|
},
|
|
165
|
-
|
|
190
|
+
PreferenceSchema: {
|
|
166
191
|
type: :object,
|
|
167
|
-
description: '
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
},
|
|
173
|
-
required: %w[key type]
|
|
174
|
-
},
|
|
175
|
-
PromotionActionCalculator: {
|
|
176
|
-
type: :object,
|
|
177
|
-
description: "The action's nested calculator (when the action carries one — null for actions like `free_shipping`)",
|
|
178
|
-
properties: {
|
|
179
|
-
type: { type: :string, example: 'flat_rate', description: 'Wire shorthand for the calculator subclass' },
|
|
180
|
-
label: { type: :string, example: 'Flat Rate' },
|
|
181
|
-
preferences: { type: :object, additionalProperties: true },
|
|
182
|
-
preference_schema: { type: :array, items: { '$ref' => '#/components/schemas/PreferenceField' } }
|
|
183
|
-
},
|
|
184
|
-
required: %w[type label preferences preference_schema]
|
|
192
|
+
description: 'The JSON Schema (draft 2020-12) of a type\'s `preferences`: one property per setting, ' \
|
|
193
|
+
'with `format` (`money`, `currency`, `iso-country`, `prefixed-id`, …), `enum`, `default`, ' \
|
|
194
|
+
'`x-spree-secret` for a secret and `x-spree-prefix` for an id list. Unknown keys are refused.',
|
|
195
|
+
additionalProperties: true,
|
|
196
|
+
example: { type: 'object', properties: { amount: { type: 'string', format: 'money', default: '0.0' } }, additionalProperties: false }
|
|
185
197
|
},
|
|
186
198
|
PromotionActionLineItem: {
|
|
187
199
|
type: :object,
|
|
@@ -243,7 +255,7 @@ module Spree
|
|
|
243
255
|
Rails.logger.warn "Failed to load Typelizer admin schemas: #{e.message}"
|
|
244
256
|
end
|
|
245
257
|
|
|
246
|
-
schemas
|
|
258
|
+
add_preference_schemas(schemas, Spree::Api::PreferenceFamilies::REGISTRIES.keys)
|
|
247
259
|
end
|
|
248
260
|
|
|
249
261
|
# Get all seller schemas (Typelizer + common).
|
|
@@ -280,7 +292,7 @@ module Spree
|
|
|
280
292
|
Rails.logger.warn "Failed to load Typelizer seller schemas: #{e.message}"
|
|
281
293
|
end
|
|
282
294
|
|
|
283
|
-
schemas
|
|
295
|
+
add_preference_schemas(schemas, Spree::Api::PreferenceFamilies::SELLER)
|
|
284
296
|
end
|
|
285
297
|
|
|
286
298
|
# Hand-written shapes the seller branch answers with that no serializer
|
|
@@ -353,45 +365,6 @@ module Spree
|
|
|
353
365
|
},
|
|
354
366
|
required: %w[status progress requirements]
|
|
355
367
|
},
|
|
356
|
-
SellerCountry: {
|
|
357
|
-
type: :object,
|
|
358
|
-
description: "A country as the panel's address forms need it",
|
|
359
|
-
properties: {
|
|
360
|
-
iso: { type: :string, example: 'US' },
|
|
361
|
-
iso3: { type: :string, example: 'USA' },
|
|
362
|
-
name: { type: :string, example: 'United States' },
|
|
363
|
-
states_required: { type: :boolean, example: true },
|
|
364
|
-
zipcode_required: { type: :boolean, example: true },
|
|
365
|
-
states: {
|
|
366
|
-
type: :array,
|
|
367
|
-
items: {
|
|
368
|
-
type: :object,
|
|
369
|
-
properties: {
|
|
370
|
-
abbr: { type: :string, example: 'CA' },
|
|
371
|
-
name: { type: :string, example: 'California' }
|
|
372
|
-
},
|
|
373
|
-
required: %w[abbr name]
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
},
|
|
377
|
-
required: %w[iso iso3 name]
|
|
378
|
-
},
|
|
379
|
-
DirectUploadResponse: {
|
|
380
|
-
type: :object,
|
|
381
|
-
description: 'A presigned upload target. PUT the file to `direct_upload.url` with the given headers, then send `signed_id` as the submission\'s `file`.',
|
|
382
|
-
properties: {
|
|
383
|
-
signed_id: { type: :string, description: 'Send this as a submission\'s `file`', example: 'eyJfcmFpbHMiOnsibWVzc2FnZSI6...' },
|
|
384
|
-
direct_upload: {
|
|
385
|
-
type: :object,
|
|
386
|
-
properties: {
|
|
387
|
-
url: { type: :string, example: 'https://storage.example.com/uploads/abc123' },
|
|
388
|
-
headers: { type: :object, additionalProperties: { type: :string } }
|
|
389
|
-
},
|
|
390
|
-
required: %w[url headers]
|
|
391
|
-
}
|
|
392
|
-
},
|
|
393
|
-
required: %w[signed_id direct_upload]
|
|
394
|
-
},
|
|
395
368
|
AuthProvidersResponse: {
|
|
396
369
|
type: :object,
|
|
397
370
|
description: 'Sign-in methods this marketplace offers sellers, for the login page',
|
|
@@ -415,17 +388,45 @@ module Spree
|
|
|
415
388
|
s[:'x-typelizer'] = true
|
|
416
389
|
strip_null_from_enums(s)
|
|
417
390
|
end
|
|
391
|
+
patch_typescript_only_types(schemas, writer_name)
|
|
418
392
|
patch_cart_schema(schemas)
|
|
419
393
|
patch_fulfillment_schema(schemas)
|
|
420
394
|
patch_admin_user_schema(schemas)
|
|
421
395
|
patch_promotion_rule_schema(schemas)
|
|
422
396
|
patch_promotion_action_schema(schemas)
|
|
423
|
-
patch_price_rule_schema(schemas)
|
|
424
397
|
patch_import_schema(schemas)
|
|
425
398
|
schemas
|
|
426
399
|
end
|
|
427
400
|
end
|
|
428
401
|
|
|
402
|
+
# Typelizer publishes a type only TypeScript can express (`Array<{ … }>`,
|
|
403
|
+
# `any`) as a plain object. Give each such property the shape the API
|
|
404
|
+
# sends — an array, or any value — so responses validate against it;
|
|
405
|
+
# the patches below then point some arrays at a named item component.
|
|
406
|
+
def patch_typescript_only_types(schemas, writer_name)
|
|
407
|
+
Typelizer.interfaces(writer_name: writer_name).each do |interface|
|
|
408
|
+
properties = (schemas[interface.name] || schemas[interface.name.to_sym])&.dig(:properties)
|
|
409
|
+
next unless properties
|
|
410
|
+
|
|
411
|
+
interface.properties.each do |property|
|
|
412
|
+
key = [property.name.to_s, property.name.to_sym].find { |name| properties.key?(name) }
|
|
413
|
+
schema = key && !property.type.is_a?(Array) && typescript_only_type_schema(property.type.to_s)
|
|
414
|
+
next unless schema
|
|
415
|
+
|
|
416
|
+
schema[:nullable] = true if property.nullable || property.type.to_s.end_with?('| null')
|
|
417
|
+
properties[key] = schema.merge(properties[key].slice(:description))
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def typescript_only_type_schema(type)
|
|
423
|
+
case type.delete_suffix(' | null')
|
|
424
|
+
when /\AArray<(string|number|boolean)>\z/ then { type: :array, items: { type: Regexp.last_match(1).to_sym } }
|
|
425
|
+
when /\AArray</ then { type: :array, items: { type: :object } }
|
|
426
|
+
when 'any', 'unknown' then {}
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
429
430
|
# Same Array<{...}> issue as cart/fulfillment — patch Import#schema_fields
|
|
430
431
|
# to reference the ImportSchemaField component schema.
|
|
431
432
|
def patch_import_schema(schemas)
|
|
@@ -504,22 +505,12 @@ module Spree
|
|
|
504
505
|
return unless rule
|
|
505
506
|
|
|
506
507
|
patch_id_arrays(rule, %w[product_ids category_ids customer_ids option_value_ids])
|
|
507
|
-
patch_preference_schema(rule)
|
|
508
|
-
end
|
|
509
|
-
|
|
510
|
-
def patch_price_rule_schema(schemas)
|
|
511
|
-
rule = schemas['PriceRule'] || schemas[:PriceRule]
|
|
512
|
-
return unless rule
|
|
513
|
-
|
|
514
|
-
patch_preference_schema(rule)
|
|
515
508
|
end
|
|
516
509
|
|
|
517
510
|
def patch_promotion_action_schema(schemas)
|
|
518
511
|
action = schemas['PromotionAction'] || schemas[:PromotionAction]
|
|
519
512
|
return unless action
|
|
520
513
|
|
|
521
|
-
patch_preference_schema(action)
|
|
522
|
-
|
|
523
514
|
props = action[:properties]
|
|
524
515
|
return unless props
|
|
525
516
|
|
|
@@ -557,17 +548,72 @@ module Spree
|
|
|
557
548
|
end
|
|
558
549
|
end
|
|
559
550
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
551
|
+
# One component per subtype Spree ships (`PromotionRuleItemTotalPreferences`)
|
|
552
|
+
# and one per family (`PromotionRulePreferences`) that the family's
|
|
553
|
+
# resource points its `preferences` at. A type an extension registers
|
|
554
|
+
# matches the final plain object; its shape is the `schema` in the
|
|
555
|
+
# family's `/types` response.
|
|
556
|
+
#
|
|
557
|
+
# @param schemas [Hash] components, changed in place
|
|
558
|
+
# @param families [Array<String>]
|
|
559
|
+
# @return [Hash] the components
|
|
560
|
+
def add_preference_schemas(schemas, families)
|
|
561
|
+
Spree::Api::PreferenceFamilies.schemas(families).each do |family, members|
|
|
562
|
+
refs = members.to_h do |type, schema|
|
|
563
|
+
name = Spree::Api::PreferenceFamilies.member_name(family, type)
|
|
564
|
+
schemas[name] = openapi_schema(schema)
|
|
565
|
+
[type, "#/components/schemas/#{name}"]
|
|
566
|
+
end
|
|
563
567
|
|
|
564
|
-
|
|
565
|
-
|
|
568
|
+
schemas["#{family}Preferences"] = {
|
|
569
|
+
description: "Settings of a #{family.titleize.downcase}, shaped by its `type` (see `x-spree-preferences-by-type`). " \
|
|
570
|
+
'A type an extension registers is a plain object, described by the `schema` its `/types` entry carries.',
|
|
571
|
+
anyOf: refs.values.map { |ref| { '$ref' => ref } } + [{ type: :object, additionalProperties: true }],
|
|
572
|
+
'x-spree-preferences-by-type' => refs
|
|
573
|
+
}
|
|
566
574
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
575
|
+
resource = schemas[family] || schemas[family.to_sym]
|
|
576
|
+
props = resource&.dig(:properties)
|
|
577
|
+
key = props&.key?('preferences') ? 'preferences' : :preferences
|
|
578
|
+
props[key] = { '$ref' => "#/components/schemas/#{family}Preferences" } if props&.key?(key)
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
# A calculator names its family's union, so it is published only
|
|
582
|
+
# alongside that union.
|
|
583
|
+
CALCULATOR_SCHEMAS.slice(*families).each_value { |name, schema| schemas[name] = schema }
|
|
584
|
+
patch_delivery_method_calculator(schemas)
|
|
585
|
+
schemas
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
# The generated JSON Schema is draft 2020-12; OpenAPI 3.0 spells a
|
|
589
|
+
# nullable type as `nullable: true` and has no `propertyNames`.
|
|
590
|
+
def openapi_schema(schema)
|
|
591
|
+
case schema
|
|
592
|
+
when Hash
|
|
593
|
+
converted = schema.each_with_object({}) do |(key, value), result|
|
|
594
|
+
next if key == 'propertyNames'
|
|
595
|
+
|
|
596
|
+
result[key] = %w[enum default required].include?(key) ? value : openapi_schema(value)
|
|
597
|
+
end
|
|
598
|
+
if schema['type'].is_a?(Array)
|
|
599
|
+
converted['type'] = (schema['type'] - ['null']).first
|
|
600
|
+
converted['nullable'] = true if schema['type'].include?('null')
|
|
601
|
+
end
|
|
602
|
+
converted['enum'] = converted['enum'].compact if converted['enum']
|
|
603
|
+
converted['x-spree-property-names'] = openapi_schema(schema['propertyNames']) if schema['propertyNames']
|
|
604
|
+
converted
|
|
605
|
+
when Array then schema.map { |item| openapi_schema(item) }
|
|
606
|
+
else schema
|
|
607
|
+
end
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
def patch_delivery_method_calculator(schemas)
|
|
611
|
+
method = schemas['DeliveryMethod'] || schemas[:DeliveryMethod]
|
|
612
|
+
props = method&.dig(:properties)
|
|
613
|
+
return unless props
|
|
614
|
+
|
|
615
|
+
key = props.key?('calculator') ? 'calculator' : :calculator
|
|
616
|
+
props[key] = { allOf: [{ '$ref' => '#/components/schemas/DeliveryMethodCalculator' }], nullable: true } if props[key]
|
|
571
617
|
end
|
|
572
618
|
|
|
573
619
|
# Typelizer cannot represent Array<{...}> inline object types in OpenAPI,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
# The configurable families whose subtypes each declare their own
|
|
4
|
+
# `preferences`: the subtypes Spree ships, keyed by their wire `type`, with
|
|
5
|
+
# the JSON Schema of each one's preferences. The OpenAPI components and the
|
|
6
|
+
# SDK's preference types are both generated from it, so the two cannot
|
|
7
|
+
# describe different shapes.
|
|
8
|
+
module PreferenceFamilies
|
|
9
|
+
# Family name => its registry. The name is the resource the family's
|
|
10
|
+
# rows are serialized as, or, for calculators, the calculator's role.
|
|
11
|
+
REGISTRIES = {
|
|
12
|
+
'CommissionRule' => -> { Spree.commission_rules },
|
|
13
|
+
'DeliveryCalculator' => -> { Spree::DeliveryMethod.calculators },
|
|
14
|
+
'DeliveryMethodRule' => -> { Spree.delivery_method_rules },
|
|
15
|
+
'Integration' => -> { Spree::Integration.registered_classes },
|
|
16
|
+
'OrderRoutingRule' => -> { Spree.order_routing.rules },
|
|
17
|
+
'PaymentMethod' => -> { Spree::PaymentMethod.providers },
|
|
18
|
+
'PriceRule' => -> { Array(Spree.pricing&.rules) },
|
|
19
|
+
'PromotionCalculator' => lambda {
|
|
20
|
+
Spree.calculators.promotion_actions_create_adjustments + Spree.calculators.promotion_actions_create_item_adjustments
|
|
21
|
+
},
|
|
22
|
+
'PromotionRule' => -> { Spree.promotions.rules },
|
|
23
|
+
'SellerRequirement' => -> { Spree.seller_requirements }
|
|
24
|
+
}.freeze
|
|
25
|
+
|
|
26
|
+
# The families a seller reads and writes.
|
|
27
|
+
SELLER = %w[DeliveryCalculator DeliveryMethodRule].freeze
|
|
28
|
+
|
|
29
|
+
# @param names [Array<String>] family names, every family by default
|
|
30
|
+
# @return [Hash{String => Hash{String => Hash}}] family => { type => JSON Schema of its preferences }
|
|
31
|
+
def self.schemas(names = REGISTRIES.keys)
|
|
32
|
+
names.to_h do |name|
|
|
33
|
+
classes = REGISTRIES.fetch(name).call.map { |entry| entry.is_a?(Class) ? entry : entry.to_s.constantize }
|
|
34
|
+
[name, classes.uniq.sort_by(&:api_type).to_h { |klass| [klass.api_type, klass.preference_json_schema] }]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @param family [String] e.g. `PromotionRule`
|
|
39
|
+
# @param type [String] e.g. `item_total`
|
|
40
|
+
# @return [String] e.g. `PromotionRuleItemTotalPreferences`
|
|
41
|
+
def self.member_name(family, type)
|
|
42
|
+
"#{family}#{type.camelize}Preferences"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
require 'spree/api/preference_families'
|
|
2
|
+
|
|
3
|
+
module Spree
|
|
4
|
+
module Api
|
|
5
|
+
# Renders each configurable family's preference schemas
|
|
6
|
+
# ({Spree::Api::PreferenceFamilies}) into the TypeScript types the Admin
|
|
7
|
+
# and Seller SDKs export: one interface per subtype Spree ships, a map from
|
|
8
|
+
# `type` to it, and the family's resource with `preferences` typed by its
|
|
9
|
+
# `type`.
|
|
10
|
+
#
|
|
11
|
+
# The map is an interface, so an extension types its own subtypes by
|
|
12
|
+
# declaration merging. A union with a catch-all member for unknown types
|
|
13
|
+
# would stop TypeScript from narrowing on `type` at all.
|
|
14
|
+
#
|
|
15
|
+
# Run by `rake typelizer:generate`; `preference_types_spec.rb` fails when
|
|
16
|
+
# the committed files no longer match the declarations.
|
|
17
|
+
class PreferenceTypes
|
|
18
|
+
HEADER = "// This file is auto-generated from Spree's preference declarations by `rake typelizer:generate`. Do not edit directly.\n".freeze
|
|
19
|
+
|
|
20
|
+
FILES = {
|
|
21
|
+
'packages/admin-sdk/src/types/preferences.ts' => PreferenceFamilies::REGISTRIES.keys,
|
|
22
|
+
'packages/seller-sdk/src/types/preferences.ts' => PreferenceFamilies::SELLER
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
# Families serialized as rows of their own; calculators are nested in
|
|
26
|
+
# their owner, whose serializer types `calculator` with `Typed<Family>`.
|
|
27
|
+
RESOURCES = (PreferenceFamilies::REGISTRIES.keys - %w[DeliveryCalculator PromotionCalculator]).freeze
|
|
28
|
+
|
|
29
|
+
# @return [Hash{String => String}] file contents keyed by path under the monorepo root
|
|
30
|
+
def render
|
|
31
|
+
FILES.transform_values { |families| source(PreferenceFamilies.schemas(families)) }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Typelizer imports a type a serializer names (`TypedDeliveryCalculator`)
|
|
35
|
+
# from its generated index, so that index re-exports these types too.
|
|
36
|
+
INDEX_EXPORT = "export type * from '../preferences'\n".freeze
|
|
37
|
+
|
|
38
|
+
# @param root [Pathname] the monorepo root
|
|
39
|
+
# @return [void]
|
|
40
|
+
def write!(root)
|
|
41
|
+
render.each do |path, content|
|
|
42
|
+
File.write(root.join(path), content)
|
|
43
|
+
|
|
44
|
+
index = root.join(path).dirname.join('generated/index.ts')
|
|
45
|
+
File.write(index, index.read + INDEX_EXPORT) if index.exist? && !index.read.include?(INDEX_EXPORT)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
NARROWED = <<~TS.freeze
|
|
52
|
+
/** `Resource` with its `preferences` typed by its `type`, one member per entry of `Map`. */
|
|
53
|
+
type Narrowed<Resource, Map> = {
|
|
54
|
+
[Type in keyof Map]: Omit<Resource, 'type' | 'preferences'> & {
|
|
55
|
+
type: Type
|
|
56
|
+
preferences: Map[Type]
|
|
57
|
+
}
|
|
58
|
+
}[keyof Map]
|
|
59
|
+
TS
|
|
60
|
+
|
|
61
|
+
def source(families)
|
|
62
|
+
resources = families.keys & RESOURCES
|
|
63
|
+
imports = resources.map { |family| "import type #{family} from './generated/#{family}'\n" }.join
|
|
64
|
+
parts = families.flat_map { |family, members| family_parts(family, members, resources.include?(family)) }
|
|
65
|
+
parts.unshift(NARROWED) if resources.any?
|
|
66
|
+
parts.unshift(imports) if imports.present?
|
|
67
|
+
|
|
68
|
+
HEADER + parts.join("\n")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def family_parts(family, members, resource)
|
|
72
|
+
label = family.titleize.downcase
|
|
73
|
+
parts = members.map do |type, schema|
|
|
74
|
+
name = PreferenceFamilies.member_name(family, type)
|
|
75
|
+
properties = schema['properties']
|
|
76
|
+
next "/** Settings of the `#{type}` #{label}: none. */\nexport type #{name} = Record<string, never>\n" if properties.empty?
|
|
77
|
+
|
|
78
|
+
fields = properties.map { |key, property| "#{field_comment(property)} #{key}: #{ts_type(property)}\n" }.join
|
|
79
|
+
# A type, not an interface, so it stays assignable to
|
|
80
|
+
# `Record<string, unknown>`, which generic preference forms take.
|
|
81
|
+
"/** Settings of the `#{type}` #{label}. */\nexport type #{name} = {\n#{fields}}\n"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
map = "#{family}PreferencesMap"
|
|
85
|
+
entries = members.keys.map { |type| " #{type}: #{PreferenceFamilies.member_name(family, type)}\n" }.join
|
|
86
|
+
ignore = members.empty? ? "// biome-ignore lint/suspicious/noEmptyInterface: extensions add their types by declaration merging\n" : ''
|
|
87
|
+
parts << "/**\n * The settings of each #{label} type Spree ships, by `type`. An interface,\n" \
|
|
88
|
+
" * so an extension types its own by declaration merging.\n */\n" \
|
|
89
|
+
"#{ignore}export interface #{map} {#{"\n#{entries}" if entries.present?}}\n"
|
|
90
|
+
article = label.match?(/\A[aeiou]/) ? 'An' : 'A'
|
|
91
|
+
parts << if resource
|
|
92
|
+
"/** #{article} #{label} whose `preferences` are typed by its `type`. */\nexport type Typed#{family} = Narrowed<#{family}, #{map}>\n"
|
|
93
|
+
else
|
|
94
|
+
# A calculator is nested in its owner, which types its
|
|
95
|
+
# `calculator` field with this union.
|
|
96
|
+
"/** #{article} #{label}, its `preferences` typed by its `type`. */\n" \
|
|
97
|
+
"export type Typed#{family} = {\n [Type in keyof #{map}]: {\n type: Type\n preferences: #{map}[Type]\n }\n}[keyof #{map}]\n"
|
|
98
|
+
end
|
|
99
|
+
parts
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def field_comment(property)
|
|
103
|
+
note = if property['x-spree-secret'] then 'Masked when read (`••••1234`); send it back unchanged to keep it, `null` to clear it.'
|
|
104
|
+
elsif property.dig('items', 'x-spree-prefix') then "Prefixed `#{property.dig('items', 'x-spree-prefix')}_` ids."
|
|
105
|
+
elsif property['format'] == 'money' then 'An amount, as an exact decimal string.'
|
|
106
|
+
elsif property['format'] then "Format: `#{property['format']}`."
|
|
107
|
+
end
|
|
108
|
+
note ? " /** #{note} */\n" : ''
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def ts_type(schema)
|
|
112
|
+
types = Array(schema['type'])
|
|
113
|
+
base = base_type(schema, (types - ['null']).first)
|
|
114
|
+
types.include?('null') ? "#{base} | null" : base
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def base_type(schema, type)
|
|
118
|
+
return schema['enum'].compact.map { |value| value.is_a?(String) ? "'#{value}'" : value.to_s }.join(' | ') if schema['enum']
|
|
119
|
+
|
|
120
|
+
case type
|
|
121
|
+
when 'string' then 'string'
|
|
122
|
+
when 'integer', 'number' then 'number'
|
|
123
|
+
when 'boolean' then 'boolean'
|
|
124
|
+
when 'array' then schema['items'] ? "Array<#{ts_type(schema['items'])}>" : 'Array<unknown>'
|
|
125
|
+
when 'object'
|
|
126
|
+
if schema['properties']
|
|
127
|
+
"{ #{schema['properties'].map { |key, property| "#{key}: #{ts_type(property)}" }.join('; ')} }"
|
|
128
|
+
elsif schema['additionalProperties'].is_a?(Hash)
|
|
129
|
+
"Record<string, #{ts_type(schema['additionalProperties'])}>"
|
|
130
|
+
else
|
|
131
|
+
'Record<string, unknown>'
|
|
132
|
+
end
|
|
133
|
+
else 'unknown'
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -29,6 +29,10 @@ module Spree
|
|
|
29
29
|
# The typed webhook events in @spree/sdk, from the event catalog.
|
|
30
30
|
require Spree::Api::Engine.root.join('lib/spree/api/webhook_event_types').to_s
|
|
31
31
|
Spree::Api::WebhookEventTypes.new.write!(api_root.join('../..'))
|
|
32
|
+
|
|
33
|
+
# Each configurable family's preferences, typed by `type`, in the Admin and Seller SDKs.
|
|
34
|
+
require Spree::Api::Engine.root.join('lib/spree/api/preference_types').to_s
|
|
35
|
+
Spree::Api::PreferenceTypes.new.write!(api_root.join('../..'))
|
|
32
36
|
end
|
|
33
37
|
end
|
|
34
38
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
namespace :spree do
|
|
2
|
+
namespace :api do
|
|
3
|
+
desc 'Print the filter tables of every list endpoint, as JSON, for `spree filters types`'
|
|
4
|
+
task filter_tables: :environment do
|
|
5
|
+
Rails.application.eager_load!
|
|
6
|
+
apis = %w[store admin seller].index_with { |api| Spree::Api::V3::FilterTable.spec_for(api) }
|
|
7
|
+
|
|
8
|
+
# One line: the CLI drops boot noise line by line.
|
|
9
|
+
puts apis.to_json
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/typelizer/open_enums.rb
CHANGED
|
@@ -7,10 +7,19 @@ module Typelizer
|
|
|
7
7
|
# open, and the OpenAPI property becomes an open enum, so a client generated
|
|
8
8
|
# from either still accepts an added value while every built-in value stays
|
|
9
9
|
# documented and autocompletable.
|
|
10
|
+
#
|
|
11
|
+
# ISO lists are the exception: a named type several serializers and the
|
|
12
|
+
# request types share, but closed, since nothing outside the standard can
|
|
13
|
+
# add a country or a currency, and markets only accept the locales
|
|
14
|
+
# `Spree::Locales::ALL` lists.
|
|
10
15
|
module OpenEnums
|
|
16
|
+
CLOSED_TYPE_NAMES = %w[CountryCode CurrencyCode LocaleCode].freeze
|
|
17
|
+
|
|
11
18
|
module Property
|
|
12
19
|
def enum_definition(...)
|
|
13
20
|
definition = super
|
|
21
|
+
return definition if CLOSED_TYPE_NAMES.include?(enum_type_name)
|
|
22
|
+
|
|
14
23
|
definition && "#{definition} | (string & {})"
|
|
15
24
|
end
|
|
16
25
|
end
|
|
@@ -20,6 +29,7 @@ module Typelizer
|
|
|
20
29
|
|
|
21
30
|
def inline_schema(definition, property, openapi_version:)
|
|
22
31
|
return super unless property.enum_type_name && property.enum.is_a?(Array) && !property.multi
|
|
32
|
+
return super if CLOSED_TYPE_NAMES.include?(property.enum_type_name)
|
|
23
33
|
|
|
24
34
|
open = { anyOf: [{ type: :string, enum: property.enum.compact }, { type: :string }] }
|
|
25
35
|
apply_nullable(open, property, openapi_version: openapi_version)
|