spree_api 6.0.0.rc4 → 6.0.0.rc5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/concerns/spree/api/v3/allowed_redirect_url.rb +27 -0
- data/app/controllers/concerns/spree/api/v3/cart_resolvable.rb +8 -2
- data/app/controllers/concerns/spree/api/v3/scoped_authorization.rb +6 -2
- data/app/controllers/spree/api/v3/admin/companies/addresses_controller.rb +7 -1
- data/app/controllers/spree/api/v3/admin/custom_fields_controller.rb +30 -8
- data/app/controllers/spree/api/v3/admin/customers/addresses_controller.rb +4 -0
- data/app/controllers/spree/api/v3/admin/customers_controller.rb +1 -6
- data/app/controllers/spree/api/v3/admin/gift_cards_controller.rb +1 -8
- data/app/controllers/spree/api/v3/admin/orders_controller.rb +11 -5
- data/app/controllers/spree/api/v3/admin/package_types_controller.rb +2 -3
- data/app/controllers/spree/api/v3/admin/products/variants_controller.rb +3 -4
- data/app/controllers/spree/api/v3/admin/products_controller.rb +5 -3
- data/app/controllers/spree/api/v3/admin/store_controller.rb +1 -1
- data/app/controllers/spree/api/v3/admin/variants_controller.rb +96 -1
- data/app/controllers/spree/api/v3/oauth/authorizations_controller.rb +17 -6
- data/app/controllers/spree/api/v3/resource_controller.rb +35 -5
- data/app/controllers/spree/api/v3/seller/package_types_controller.rb +2 -2
- data/app/controllers/spree/api/v3/seller/products_controller.rb +7 -61
- data/app/controllers/spree/api/v3/seller/resource_controller.rb +2 -6
- data/app/controllers/spree/api/v3/store/carts/addresses_controller.rb +53 -0
- data/app/controllers/spree/api/v3/store/carts_controller.rb +3 -3
- data/app/controllers/spree/api/v3/store/companies/addresses_controller.rb +4 -0
- data/app/controllers/spree/api/v3/store/customer/addresses_controller.rb +4 -0
- data/app/controllers/spree/api/v3/store/customer/data_requests_controller.rb +19 -1
- data/app/controllers/spree/api/v3/store/customer/password_resets_controller.rb +3 -14
- data/app/controllers/spree/api/v3/store/data_request_confirmations_controller.rb +23 -0
- data/app/controllers/spree/api/v3/store/data_requests_controller.rb +56 -0
- data/app/controllers/spree/api/v3/store/newsletter_subscribers_controller.rb +2 -11
- data/app/request_schemas/spree/api/v3/admin/variant_request_schema.rb +21 -0
- data/app/request_schemas/spree/api/v3/seller/price_request_schema.rb +20 -0
- data/app/request_schemas/spree/api/v3/seller/variant_request_schema.rb +19 -0
- data/app/request_schemas/spree/api/v3/variant_request_schema.rb +8 -13
- data/app/serializers/spree/api/v3/address_owner_serializer.rb +27 -0
- data/app/serializers/spree/api/v3/address_serializer.rb +5 -1
- data/app/serializers/spree/api/v3/admin/address_owner_serializer.rb +10 -0
- data/app/serializers/spree/api/v3/admin/address_serializer.rb +1 -10
- data/app/serializers/spree/api/v3/admin/api_key_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/catalog_assignment_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/catalog_price_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/collection_rule_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/collection_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/commission_line_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/admin/commission_rate_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/consent_record_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/email_template_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/order_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/package_type_serializer.rb +3 -3
- data/app/serializers/spree/api/v3/admin/permission_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/price_list_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/purchase_order_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/seller_requirement_status_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/seller_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/admin/seller_transfer_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/shipping_label_serializer.rb +3 -3
- data/app/serializers/spree/api/v3/admin/stock_location_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/stock_receipt_item_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/admin/stock_receipt_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/stock_transfer_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/store_serializer.rb +1 -0
- data/app/serializers/spree/api/v3/admin/tax_identifier_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/admin/tax_line_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/variant_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/base_serializer.rb +27 -5
- data/app/serializers/spree/api/v3/claim_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/collection_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/company_invitation_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/company_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/data_request_confirmation_requested_event_serializer.rb +28 -0
- data/app/serializers/spree/api/v3/data_request_event_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/data_request_serializer.rb +8 -4
- data/app/serializers/spree/api/v3/delivery_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/delivery_zone_member_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/discount_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/file_upload_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/fulfillment_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/media_event_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/media_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/option_type_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/order_group_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/order_serializer.rb +4 -2
- data/app/serializers/spree/api/v3/payment_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/product_filter_availability_option_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/product_filter_option_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/seller/address_serializer.rb +3 -2
- data/app/serializers/spree/api/v3/seller/order_serializer.rb +3 -3
- data/app/serializers/spree/api/v3/seller/package_type_serializer.rb +3 -3
- data/app/serializers/spree/api/v3/seller/profile_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/seller/requirement_status_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/seller/tax_identifier_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/seller/variant_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/shipping_label_event_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/stock_movement_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/stock_receipt_event_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/variant_serializer.rb +2 -2
- data/app/services/spree/api/v3/filter_table.rb +22 -3
- data/app/services/spree/api/v3/request_schema.rb +64 -17
- data/config/locales/en.yml +1 -0
- data/config/routes.rb +19 -11
- data/lib/spree/api/agent_write_schemas.rb +15 -3
- data/lib/spree/api/dependencies.rb +2 -2
- data/lib/spree/api/enum_types.rb +118 -0
- data/lib/spree/api/openapi/filter_documentation.rb +8 -1
- data/lib/spree/api/typelizer_generation.rb +5 -0
- data/lib/typelizer/open_enums.rb +40 -16
- metadata +17 -6
|
@@ -15,14 +15,14 @@ module Spree
|
|
|
15
15
|
# refuses to write them (docs/plans/6.0-seller-package-types.md).
|
|
16
16
|
class PackageTypeSerializer < V3::BaseSerializer
|
|
17
17
|
typelize name: :string,
|
|
18
|
-
kind: [:string, enum: Spree::PackageType::KINDS],
|
|
18
|
+
kind: [:string, enum: Spree::PackageType::KINDS, enum_type_name: 'PackageTypeKind'],
|
|
19
19
|
length: [:string, nullable: true],
|
|
20
20
|
width: [:string, nullable: true],
|
|
21
21
|
height: [:string, nullable: true],
|
|
22
|
-
dimensions_unit: [:string, enum: Spree::Variant::DIMENSION_UNITS],
|
|
22
|
+
dimensions_unit: [:string, enum: Spree::Variant::DIMENSION_UNITS, enum_type_name: 'DimensionUnit'],
|
|
23
23
|
weight: [:string, nullable: true],
|
|
24
24
|
max_weight: [:string, nullable: true],
|
|
25
|
-
weight_unit: [:string, enum: Spree::Variant::WEIGHT_UNITS],
|
|
25
|
+
weight_unit: [:string, enum: Spree::Variant::WEIGHT_UNITS, enum_type_name: 'WeightUnit'],
|
|
26
26
|
volume: [:string, nullable: true],
|
|
27
27
|
default: :boolean,
|
|
28
28
|
editable: :boolean,
|
|
@@ -8,8 +8,8 @@ module Spree
|
|
|
8
8
|
registration_number: [:string, nullable: true],
|
|
9
9
|
contact_email: [:string, nullable: true],
|
|
10
10
|
billing_email: [:string, nullable: true],
|
|
11
|
-
tax_remittance: :string,
|
|
12
|
-
payouts_schedule_interval: [:string, nullable: true],
|
|
11
|
+
tax_remittance: [:string, enum: Spree::Seller::TAX_REMITTANCES, enum_type_name: 'TaxRemittance'],
|
|
12
|
+
payouts_schedule_interval: [:string, nullable: true, enum: Spree::Seller::PAYOUT_INTERVALS, enum_type_name: 'PayoutScheduleInterval'],
|
|
13
13
|
minimum_payout_amount: [:string, nullable: true],
|
|
14
14
|
holiday_mode_until: [:string, nullable: true],
|
|
15
15
|
terms_accepted_at: [:string, nullable: true],
|
|
@@ -8,7 +8,7 @@ module Spree
|
|
|
8
8
|
|
|
9
9
|
typelize id: :string, kind: [:string, comment: 'Requirement kind. Built-in: accept_terms, complete_profile, billing_address, returns_address, delivery_method, package_type, minimum_products, payout_account, required_custom_fields, policy, attestation, operator_review, document. Extensions may register more.'], name: :string,
|
|
10
10
|
description: [:string, nullable: true],
|
|
11
|
-
required: :boolean, position: :number, status: [:string, enum: Spree::SellerRequirementStatus::STATUSES],
|
|
11
|
+
required: :boolean, position: :number, status: [:string, enum: Spree::SellerRequirementStatus::STATUSES, enum_type_name: 'SellerRequirementState'],
|
|
12
12
|
blocking: :boolean, action_url: [:string, nullable: true],
|
|
13
13
|
blocker: ['{ state: string; message: string | null } | null'],
|
|
14
14
|
accepts_submissions: :boolean, requires_file: :boolean,
|
|
@@ -4,7 +4,7 @@ module Spree
|
|
|
4
4
|
module Seller
|
|
5
5
|
class TaxIdentifierSerializer < V3::BaseSerializer
|
|
6
6
|
typelize kind: [:string, comment: 'Tax identifier kind, keyed to a registered validator. Built-in: eu_vat. Extensions may register more.'], value: :string,
|
|
7
|
-
validation_status: [:string, nullable: true, enum: Spree::TaxIdentifier::VALIDATION_STATUSES],
|
|
7
|
+
validation_status: [:string, nullable: true, enum: Spree::TaxIdentifier::VALIDATION_STATUSES, enum_type_name: 'TaxIdentifierValidationStatus'],
|
|
8
8
|
validated_at: [:string, nullable: true]
|
|
9
9
|
|
|
10
10
|
attributes :kind, :value, :validation_status, validated_at: :iso8601
|
|
@@ -25,7 +25,7 @@ module Spree
|
|
|
25
25
|
country_of_origin: [:string, nullable: true, enum: Spree::IsoData.country_codes, enum_type_name: 'CountryCode'],
|
|
26
26
|
customs_description: [:string, nullable: true],
|
|
27
27
|
minimum_order_quantity: ['number | null'], order_multiple: ['number | null'],
|
|
28
|
-
purchase_unit: [:string, nullable: true, enum: Spree::Variant::PURCHASE_UNITS],
|
|
28
|
+
purchase_unit: [:string, nullable: true, enum: Spree::Variant::PURCHASE_UNITS, enum_type_name: 'PurchaseUnit'],
|
|
29
29
|
metadata: 'Record<string, unknown>'
|
|
30
30
|
|
|
31
31
|
attributes :metadata, :position, :cost_currency,
|
|
@@ -6,7 +6,7 @@ module Spree
|
|
|
6
6
|
# stay behind the Admin API.
|
|
7
7
|
class ShippingLabelEventSerializer < BaseSerializer
|
|
8
8
|
typelize owner_id: :string,
|
|
9
|
-
owner_type: [:string, enum: %w[fulfillment return]],
|
|
9
|
+
owner_type: [:string, enum: %w[fulfillment return], enum_type_name: 'ShippingLabelOwnerType'],
|
|
10
10
|
status: [:string, enum: Spree::ShippingLabel.statuses, enum_type_name: 'ShippingLabelStatus'],
|
|
11
11
|
carrier: [:string, nullable: true],
|
|
12
12
|
service: [:string, nullable: true],
|
|
@@ -7,7 +7,7 @@ module Spree
|
|
|
7
7
|
# `kind` is nullable for the lifetime of 6.0: a legacy row on an
|
|
8
8
|
# install that has not run spree:migrate_stock_movements_to_typed_rows
|
|
9
9
|
# has no kind yet.
|
|
10
|
-
typelize quantity: :number, kind: [:string, nullable: true, enum: Spree::StockMovement::KINDS],
|
|
10
|
+
typelize quantity: :number, kind: [:string, nullable: true, enum: Spree::StockMovement::KINDS, enum_type_name: 'StockMovementKind'],
|
|
11
11
|
reason: [:string, nullable: true], stock_level_id: [:string, nullable: true]
|
|
12
12
|
|
|
13
13
|
attributes :quantity, :kind, :reason,
|
|
@@ -6,7 +6,7 @@ module Spree
|
|
|
6
6
|
class StockReceiptEventSerializer < BaseSerializer
|
|
7
7
|
typelize number: :string,
|
|
8
8
|
received_at: :string,
|
|
9
|
-
receivable_type: [:string, enum: %w[purchase_order stock_transfer]],
|
|
9
|
+
receivable_type: [:string, enum: %w[purchase_order stock_transfer], enum_type_name: 'StockReceiptReceivableType'],
|
|
10
10
|
receivable_id: :string,
|
|
11
11
|
quantity_accepted_total: :number,
|
|
12
12
|
quantity_rejected_total: :number
|
|
@@ -10,11 +10,11 @@ module Spree
|
|
|
10
10
|
purchasable: :boolean, in_stock: :boolean, backorderable: :boolean, preorder: :boolean,
|
|
11
11
|
preorder_ships_at: [:string, nullable: true],
|
|
12
12
|
weight: [:number, nullable: true], height: [:number, nullable: true], width: [:number, nullable: true], depth: [:number, nullable: true],
|
|
13
|
-
weight_unit: [:string, enum: Spree::Variant::WEIGHT_UNITS], dimensions_unit: [:string, enum: Spree::Variant::DIMENSION_UNITS],
|
|
13
|
+
weight_unit: [:string, enum: Spree::Variant::WEIGHT_UNITS, enum_type_name: 'WeightUnit'], dimensions_unit: [:string, enum: Spree::Variant::DIMENSION_UNITS, enum_type_name: 'DimensionUnit'],
|
|
14
14
|
price: 'Price',
|
|
15
15
|
original_price: ['Price', nullable: true],
|
|
16
16
|
minimum_order_quantity: :number, order_multiple: :number,
|
|
17
|
-
purchase_unit: [:string, enum: Spree::Variant::PURCHASE_UNITS], units_per_carton: ['number | null'],
|
|
17
|
+
purchase_unit: [:string, enum: Spree::Variant::PURCHASE_UNITS, enum_type_name: 'PurchaseUnit'], units_per_carton: ['number | null'],
|
|
18
18
|
seller_id: [:string, nullable: true]
|
|
19
19
|
|
|
20
20
|
prefixed_id_attributes :product
|
|
@@ -25,6 +25,17 @@ module Spree
|
|
|
25
25
|
boolean: 'boolean'
|
|
26
26
|
}.freeze
|
|
27
27
|
|
|
28
|
+
# Columns holding a value from one of the closed code lists the API
|
|
29
|
+
# publishes as a shared type, matched by name (`locale`,
|
|
30
|
+
# `default_locale`, `cost_currency`), so clients filter with that type,
|
|
31
|
+
# not free text.
|
|
32
|
+
CODE_TYPES = {
|
|
33
|
+
'locale' => 'LocaleCode',
|
|
34
|
+
'currency' => 'CurrencyCode',
|
|
35
|
+
'country_code' => 'CountryCode',
|
|
36
|
+
'country_of_origin' => 'CountryCode'
|
|
37
|
+
}.freeze
|
|
38
|
+
|
|
28
39
|
# Raised when an endpoint's table cannot be described — a column of a
|
|
29
40
|
# kind the contract has no predicates for, or two models sharing a name.
|
|
30
41
|
class Error < StandardError; end
|
|
@@ -124,8 +135,9 @@ module Spree
|
|
|
124
135
|
self.class.name_for(model)
|
|
125
136
|
end
|
|
126
137
|
|
|
127
|
-
# @return [Hash{String => String, Hash}] attribute => value kind,
|
|
128
|
-
# `{ 'enum' => [values] }` for a status
|
|
138
|
+
# @return [Hash{String => String, Hash}] attribute => value kind,
|
|
139
|
+
# `{ 'enum' => [values] }` for a status, or `{ 'code' => type }` for
|
|
140
|
+
# a value from a shared code list
|
|
129
141
|
def attributes
|
|
130
142
|
@attributes ||= kinds.reject { |_, kind| kind == :unclassified }.compact
|
|
131
143
|
end
|
|
@@ -210,6 +222,10 @@ module Spree
|
|
|
210
222
|
# attribute the model does not have (`position` on a table without
|
|
211
223
|
# one), `:unclassified` for one the contract cannot describe
|
|
212
224
|
def attribute_kind(attribute)
|
|
225
|
+
if (code_type = code_type(attribute))
|
|
226
|
+
return { 'code' => code_type }
|
|
227
|
+
end
|
|
228
|
+
|
|
213
229
|
aliased = model._ransack_aliases[attribute] || model.attribute_aliases[attribute]
|
|
214
230
|
return attribute_kind(aliased) if aliased
|
|
215
231
|
return ransacker_kind(model._ransackers[attribute]) if model._ransackers.key?(attribute)
|
|
@@ -220,7 +236,6 @@ module Spree
|
|
|
220
236
|
if (values = inclusion_values(attribute))
|
|
221
237
|
return { 'enum' => values }
|
|
222
238
|
end
|
|
223
|
-
|
|
224
239
|
column = model.columns_hash[attribute]
|
|
225
240
|
return COLUMN_KINDS.fetch(column.type, :unclassified) if column
|
|
226
241
|
return 'text' if translated_attribute?(attribute)
|
|
@@ -229,6 +244,10 @@ module Spree
|
|
|
229
244
|
:unclassified
|
|
230
245
|
end
|
|
231
246
|
|
|
247
|
+
def code_type(attribute)
|
|
248
|
+
CODE_TYPES.find { |name, _| attribute == name || attribute.end_with?("_#{name}") }&.last
|
|
249
|
+
end
|
|
250
|
+
|
|
232
251
|
# The fixed list an inclusion validation allows, for a column that
|
|
233
252
|
# holds one of a known set of values (`payment_status`, `kind`).
|
|
234
253
|
def inclusion_values(attribute)
|
|
@@ -40,20 +40,24 @@ module Spree
|
|
|
40
40
|
datetime: { type: :string, format: :'date-time' },
|
|
41
41
|
id: { type: :string },
|
|
42
42
|
any: {},
|
|
43
|
-
#
|
|
43
|
+
# Codes from the closed lists below.
|
|
44
44
|
country: { type: :string },
|
|
45
45
|
currency: { type: :string },
|
|
46
|
-
locale: { type: :string }
|
|
46
|
+
locale: { type: :string },
|
|
47
|
+
weight_unit: { type: :string },
|
|
48
|
+
dimension_unit: { type: :string }
|
|
47
49
|
}.freeze
|
|
48
50
|
|
|
49
|
-
# The
|
|
50
|
-
#
|
|
51
|
-
# `
|
|
52
|
-
#
|
|
51
|
+
# The closed lists a code field takes, published once per API as a
|
|
52
|
+
# named component — the same `CountryCode`, `CurrencyCode` and
|
|
53
|
+
# `WeightUnit` types the serializers declare, so a value read from a
|
|
54
|
+
# response is the type a request takes.
|
|
53
55
|
CODE_LISTS = {
|
|
54
56
|
country: ['CountryCode', -> { Spree::IsoData.country_codes }],
|
|
55
57
|
currency: ['CurrencyCode', -> { Spree::Money::Rounding::CURRENCY_CODES }],
|
|
56
|
-
locale: ['LocaleCode', -> { Spree::Locales::ALL }]
|
|
58
|
+
locale: ['LocaleCode', -> { Spree::Locales::ALL }],
|
|
59
|
+
weight_unit: ['WeightUnit', -> { Spree::Variant::WEIGHT_UNITS }],
|
|
60
|
+
dimension_unit: ['DimensionUnit', -> { Spree::Variant::DIMENSION_UNITS }]
|
|
57
61
|
}.freeze
|
|
58
62
|
|
|
59
63
|
ACTIONS = %i[create update].freeze
|
|
@@ -119,7 +123,7 @@ module Spree
|
|
|
119
123
|
end
|
|
120
124
|
end
|
|
121
125
|
|
|
122
|
-
attr_reader :name, :fields
|
|
126
|
+
attr_reader :name, :fields, :base
|
|
123
127
|
|
|
124
128
|
# The types an attribute takes: the scalars above, plus `:hash` (any
|
|
125
129
|
# keys), `:object` (a block or a `shape:`) and `:array` (`of:` a type
|
|
@@ -172,7 +176,7 @@ module Spree
|
|
|
172
176
|
value.is_a?(Class) ? value.definition : value
|
|
173
177
|
end
|
|
174
178
|
|
|
175
|
-
%i[attribute include_attributes require_attributes external_references].each do |method|
|
|
179
|
+
%i[attribute extends include_attributes require_attributes external_references].each do |method|
|
|
176
180
|
define_method(method) { |*args, **options, &block| definition.public_send(method, *args, **options, &block) }
|
|
177
181
|
end
|
|
178
182
|
end
|
|
@@ -229,6 +233,19 @@ module Spree
|
|
|
229
233
|
TEXT
|
|
230
234
|
end
|
|
231
235
|
|
|
236
|
+
# Builds on a published shape: the body accepts all of its attributes,
|
|
237
|
+
# and the published type is that shape's type plus what this schema
|
|
238
|
+
# adds, so clients write one type wherever the shape is accepted.
|
|
239
|
+
#
|
|
240
|
+
# @param other [RequestSchema, Class] a shape with a published name
|
|
241
|
+
def extends(other)
|
|
242
|
+
parent = RequestSchema.resolve(other)
|
|
243
|
+
raise ArgumentError, "#{parent.class.name} has no published name to extend" unless shape?(parent)
|
|
244
|
+
|
|
245
|
+
include_attributes(parent)
|
|
246
|
+
@base = parent
|
|
247
|
+
end
|
|
248
|
+
|
|
232
249
|
# Adds the attributes of another schema, for endpoints that extend a
|
|
233
250
|
# shared set.
|
|
234
251
|
#
|
|
@@ -253,6 +270,19 @@ module Spree
|
|
|
253
270
|
@permit_lists = nil
|
|
254
271
|
end
|
|
255
272
|
|
|
273
|
+
# Replaces the description of an attribute this schema took from
|
|
274
|
+
# another, for an endpoint where it behaves differently.
|
|
275
|
+
#
|
|
276
|
+
# @param name [Symbol]
|
|
277
|
+
# @param description [String]
|
|
278
|
+
# @return [void]
|
|
279
|
+
def describe_attribute(name, description)
|
|
280
|
+
field = fields.fetch(name) { raise ArgumentError, "#{name} is not an attribute of this schema" }
|
|
281
|
+
copy = field.dup
|
|
282
|
+
copy.instance_variable_set(:@description, description)
|
|
283
|
+
fields[name] = copy
|
|
284
|
+
end
|
|
285
|
+
|
|
256
286
|
# The `params.permit` list for an action.
|
|
257
287
|
#
|
|
258
288
|
# @param action [Symbol, String, nil] `create` or `update`; nil
|
|
@@ -269,12 +299,21 @@ module Spree
|
|
|
269
299
|
# @return [Hash]
|
|
270
300
|
def json_schema(action = nil)
|
|
271
301
|
action = action&.to_sym
|
|
272
|
-
|
|
273
|
-
|
|
302
|
+
# A base field this action does not take would still reach clients
|
|
303
|
+
# through the base's type, so such a body is published in full.
|
|
304
|
+
unless base && base.fields.each_value.all? { |field| field.accepted_on?(action) }
|
|
305
|
+
return object_schema(fields_for(action), action)
|
|
306
|
+
end
|
|
274
307
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
308
|
+
# Attributes the base describes the same way for this action are
|
|
309
|
+
# left to its type.
|
|
310
|
+
own = fields_for(action).reject do |field|
|
|
311
|
+
inherited = base.fields[field.name]
|
|
312
|
+
inherited && inherited.required_on?(action) == field.required_on?(action) &&
|
|
313
|
+
property_schema(inherited) == property_schema(field)
|
|
314
|
+
end
|
|
315
|
+
reference = { '$ref': "#/components/schemas/#{base.name}" }
|
|
316
|
+
own.any? ? { allOf: [reference, object_schema(own, action)] } : reference
|
|
278
317
|
end
|
|
279
318
|
|
|
280
319
|
# The component name published for an action.
|
|
@@ -291,15 +330,15 @@ module Spree
|
|
|
291
330
|
#
|
|
292
331
|
# @return [Array<RequestSchema>]
|
|
293
332
|
def shapes
|
|
294
|
-
fields.each_value.flat_map do |field|
|
|
333
|
+
(base ? [base, *base.shapes] : []).concat(fields.each_value.flat_map do |field|
|
|
295
334
|
next [] unless field.schema
|
|
296
335
|
|
|
297
336
|
nested = field.schema.shapes
|
|
298
337
|
shape?(field.schema) ? [field.schema, *nested] : nested
|
|
299
|
-
end.uniq
|
|
338
|
+
end).uniq
|
|
300
339
|
end
|
|
301
340
|
|
|
302
|
-
# The
|
|
341
|
+
# The code lists this schema's fields reach, nested ones included,
|
|
303
342
|
# as the components they publish.
|
|
304
343
|
#
|
|
305
344
|
# @return [Hash{String => Hash}]
|
|
@@ -374,6 +413,14 @@ module Spree
|
|
|
374
413
|
end
|
|
375
414
|
|
|
376
415
|
|
|
416
|
+
def object_schema(fields, action)
|
|
417
|
+
required = fields.select { |field| field.required_on?(action) }.map { |field| field.name.to_s }
|
|
418
|
+
|
|
419
|
+
schema = { type: :object, properties: fields.to_h { |field| [field.name, property_schema(field)] } }
|
|
420
|
+
schema[:required] = required if required.any?
|
|
421
|
+
schema
|
|
422
|
+
end
|
|
423
|
+
|
|
377
424
|
def fields_for(action)
|
|
378
425
|
fields.values.select { |field| field.accepted_on?(action) }
|
|
379
426
|
end
|
data/config/locales/en.yml
CHANGED
|
@@ -14,6 +14,7 @@ en:
|
|
|
14
14
|
media_in_use: This file is still in use (%{places}). Pass detach=true to remove it everywhere and delete it, or clear those places first.
|
|
15
15
|
media_not_deleted: The file could not be deleted. Nothing was changed.
|
|
16
16
|
media_url_import_requires_product: Importing media from a URL needs a product to import it into. Upload the file instead, or post it to a product's media.
|
|
17
|
+
order_sales_context_exclusive: An order already fixes its sales context, so order_id cannot be combined with %{params}.
|
|
17
18
|
store_mismatch: The requested store does not match the store this API key belongs to.
|
|
18
19
|
storefront_login_required: Authentication required to access this store.
|
|
19
20
|
unsupported_export_type: 'Unsupported export type. Supported types: %{types}'
|
data/config/routes.rb
CHANGED
|
@@ -43,6 +43,7 @@ Spree::Core::Engine.add_routes do
|
|
|
43
43
|
patch :associate
|
|
44
44
|
post :complete
|
|
45
45
|
end
|
|
46
|
+
resources :addresses, only: [:index], controller: 'carts/addresses'
|
|
46
47
|
resources :items, only: [:create, :update, :destroy], controller: 'carts/items'
|
|
47
48
|
resources :discount_codes, only: [:create, :destroy], controller: 'carts/discount_codes'
|
|
48
49
|
resources :gift_cards, only: [:create, :destroy], controller: 'carts/gift_cards'
|
|
@@ -154,6 +155,10 @@ Spree::Core::Engine.add_routes do
|
|
|
154
155
|
# Token-addressed so the emailed link works from a device that was
|
|
155
156
|
# never signed in.
|
|
156
157
|
get 'data_requests/:token/download', to: 'data_request_downloads#show', as: :data_request_download
|
|
158
|
+
# Addressed by the confirmation token emailed to the address a
|
|
159
|
+
# customer's own request names, for the same reason.
|
|
160
|
+
get 'data_requests/:token', to: 'data_requests#show', as: :data_request
|
|
161
|
+
post 'data_requests/:token/confirmation', to: 'data_request_confirmations#create', as: :data_request_confirmation
|
|
157
162
|
# Legacy path — emailed and bookmarked URLs outlive the rename. Removed in 6.1.
|
|
158
163
|
get 'digitals/:token', to: 'digital_links#show', as: :digital_download
|
|
159
164
|
|
|
@@ -282,6 +287,9 @@ Spree::Core::Engine.add_routes do
|
|
|
282
287
|
resource :store, only: [:show, :update], controller: 'store' do
|
|
283
288
|
get :data_sources
|
|
284
289
|
end
|
|
290
|
+
# The store's own custom fields, addressed by its id like every other
|
|
291
|
+
# parent. The controller only ever resolves the current store.
|
|
292
|
+
resources :stores, only: [], concerns: :custom_fieldable
|
|
285
293
|
|
|
286
294
|
# Staff & access (invitations, admin users, roles, API keys)
|
|
287
295
|
resources :admin_users, only: [:index, :show, :update, :destroy]
|
|
@@ -345,7 +353,7 @@ Spree::Core::Engine.add_routes do
|
|
|
345
353
|
end
|
|
346
354
|
|
|
347
355
|
# Products
|
|
348
|
-
resources :product_types do
|
|
356
|
+
resources :product_types, concerns: :custom_fieldable do
|
|
349
357
|
post :apply_to_products, on: :member
|
|
350
358
|
end
|
|
351
359
|
resources :products, concerns: [:custom_fieldable, :translatable] do
|
|
@@ -387,7 +395,7 @@ Spree::Core::Engine.add_routes do
|
|
|
387
395
|
# Media library — every file in the store, placed or not. Files are put
|
|
388
396
|
# ON a product through the nested media routes above; this is where they
|
|
389
397
|
# are uploaded, browsed and deleted.
|
|
390
|
-
resources :media, controller: 'media_library', only: [:index, :show, :create, :update, :destroy] do
|
|
398
|
+
resources :media, controller: 'media_library', only: [:index, :show, :create, :update, :destroy], concerns: :custom_fieldable do
|
|
391
399
|
get :usage, on: :member
|
|
392
400
|
end
|
|
393
401
|
|
|
@@ -422,7 +430,7 @@ Spree::Core::Engine.add_routes do
|
|
|
422
430
|
resources :tax_categories
|
|
423
431
|
|
|
424
432
|
# Tax Rates — the internal tax provider's configuration
|
|
425
|
-
resources :tax_rates
|
|
433
|
+
resources :tax_rates, concerns: :custom_fieldable
|
|
426
434
|
|
|
427
435
|
# Selectable tax engines and their declared limits (discovery only)
|
|
428
436
|
resources :tax_providers, only: [:index]
|
|
@@ -447,7 +455,7 @@ Spree::Core::Engine.add_routes do
|
|
|
447
455
|
post :bulk_upsert, on: :collection
|
|
448
456
|
end
|
|
449
457
|
resources :stock_movements, only: [:index, :show]
|
|
450
|
-
resources :stock_transfers do
|
|
458
|
+
resources :stock_transfers, concerns: :custom_fieldable do
|
|
451
459
|
member do
|
|
452
460
|
patch :mark_ready
|
|
453
461
|
patch :mark_in_transit
|
|
@@ -460,7 +468,7 @@ Spree::Core::Engine.add_routes do
|
|
|
460
468
|
|
|
461
469
|
# Purchasing
|
|
462
470
|
resources :suppliers
|
|
463
|
-
resources :purchase_orders do
|
|
471
|
+
resources :purchase_orders, concerns: :custom_fieldable do
|
|
464
472
|
member do
|
|
465
473
|
patch :mark_ordered
|
|
466
474
|
patch :mark_draft
|
|
@@ -471,7 +479,7 @@ Spree::Core::Engine.add_routes do
|
|
|
471
479
|
end
|
|
472
480
|
|
|
473
481
|
# Payment Methods
|
|
474
|
-
resources :delivery_methods do
|
|
482
|
+
resources :delivery_methods, concerns: :custom_fieldable do
|
|
475
483
|
collection do
|
|
476
484
|
get :calculators
|
|
477
485
|
get :fulfillment_providers
|
|
@@ -492,7 +500,7 @@ Spree::Core::Engine.add_routes do
|
|
|
492
500
|
only: [:index, :show, :create, :update, :destroy]
|
|
493
501
|
end
|
|
494
502
|
|
|
495
|
-
resources :payment_methods do
|
|
503
|
+
resources :payment_methods, concerns: :custom_fieldable do
|
|
496
504
|
get :types, on: :collection
|
|
497
505
|
end
|
|
498
506
|
|
|
@@ -502,7 +510,7 @@ Spree::Core::Engine.add_routes do
|
|
|
502
510
|
end
|
|
503
511
|
|
|
504
512
|
# Promotions, with nested actions/rules/coupon codes.
|
|
505
|
-
resources :promotions do
|
|
513
|
+
resources :promotions, concerns: :custom_fieldable do
|
|
506
514
|
resources :promotion_actions, only: [:index, :show, :create, :update, :destroy]
|
|
507
515
|
resources :promotion_rules, only: [:index, :show, :create, :update, :destroy]
|
|
508
516
|
resources :coupon_codes, only: [:index, :show]
|
|
@@ -635,7 +643,7 @@ Spree::Core::Engine.add_routes do
|
|
|
635
643
|
# Business customers — a tree of company nodes. Nested collections are
|
|
636
644
|
# listed and created under their node and then addressed directly, so
|
|
637
645
|
# a caller holding an entry id does not have to know its company.
|
|
638
|
-
resources :companies do
|
|
646
|
+
resources :companies, concerns: :custom_fieldable do
|
|
639
647
|
# The node's address book.
|
|
640
648
|
resources :addresses, controller: 'companies/addresses'
|
|
641
649
|
|
|
@@ -720,12 +728,12 @@ Spree::Core::Engine.add_routes do
|
|
|
720
728
|
end
|
|
721
729
|
|
|
722
730
|
# Gift cards
|
|
723
|
-
resources :gift_cards
|
|
731
|
+
resources :gift_cards, concerns: :custom_fieldable
|
|
724
732
|
resources :gift_card_batches, only: [:index, :show, :create]
|
|
725
733
|
|
|
726
734
|
# Store credits across all customers. Read-only: issuing, editing and
|
|
727
735
|
# deleting a credit stays nested under the customer that holds it.
|
|
728
|
-
resources :store_credits, only: [:index, :show] do
|
|
736
|
+
resources :store_credits, only: [:index, :show], concerns: :custom_fieldable do
|
|
729
737
|
resources :events, only: [:index], controller: 'store_credits/events'
|
|
730
738
|
end
|
|
731
739
|
|
|
@@ -100,19 +100,31 @@ module Spree
|
|
|
100
100
|
|
|
101
101
|
# A request body is declared once per endpoint and published as a
|
|
102
102
|
# component, so the operation carries a `$ref` to it rather than the
|
|
103
|
-
# properties themselves.
|
|
104
|
-
#
|
|
103
|
+
# properties themselves. A body that builds on a shared shape is an
|
|
104
|
+
# `allOf` of that shape and its own fields, read as one object.
|
|
105
|
+
# Followed a few hops, which is as deep as the generated document
|
|
106
|
+
# nests them.
|
|
105
107
|
#
|
|
106
108
|
# @param schema [Hash, nil] a schema that may be a reference
|
|
107
109
|
# @return [Hash, nil] the schema it names
|
|
108
110
|
def resolve_schema(schema, depth = 0)
|
|
109
111
|
return unless schema.is_a?(Hash)
|
|
110
|
-
return schema unless schema.key?('$ref')
|
|
111
112
|
return if depth > 3
|
|
113
|
+
return merge_all_of(schema['allOf'], depth) if schema.key?('allOf')
|
|
114
|
+
return schema unless schema.key?('$ref')
|
|
112
115
|
|
|
113
116
|
name = schema['$ref'].to_s.split('/').last
|
|
114
117
|
resolve_schema(document.dig('components', 'schemas', name), depth + 1)
|
|
115
118
|
end
|
|
119
|
+
|
|
120
|
+
private
|
|
121
|
+
|
|
122
|
+
def merge_all_of(parts, depth)
|
|
123
|
+
parts.filter_map { |part| resolve_schema(part, depth + 1) }.each_with_object({}) do |part, merged|
|
|
124
|
+
merged['properties'] = (merged['properties'] || {}).merge(part['properties'] || {})
|
|
125
|
+
merged['required'] = (merged['required'] || []) | Array(part['required'])
|
|
126
|
+
end
|
|
127
|
+
end
|
|
116
128
|
end
|
|
117
129
|
end
|
|
118
130
|
end
|
|
@@ -9,7 +9,7 @@ module Spree
|
|
|
9
9
|
STORE_SERIALIZERS =
|
|
10
10
|
%i[credit_card price price_history product product_type variant media option_type option_value cart order
|
|
11
11
|
order_group line_item payment payment_session payment_setup_session payment_source store_credit
|
|
12
|
-
fulfillment delivery address customer data_request customer_group country channel product_publication
|
|
12
|
+
fulfillment delivery address address_owner customer data_request customer_group country channel product_publication
|
|
13
13
|
market state wishlist wishlist_item payment_method delivery_method delivery_rate freight_summary
|
|
14
14
|
stock_location category collection applied_promotion discount tax_line delivery_zone delivery_zone_member
|
|
15
15
|
fee digital_link gift_card currency locale policy custom_field tax_category tax_identifier
|
|
@@ -34,7 +34,7 @@ module Spree
|
|
|
34
34
|
catalog_product price_list_product catalog_assignment catalog_quantity_rule catalog_product_term
|
|
35
35
|
catalog_order_minimum tax_exemption_certificate tax_exemption_reason admin_user actor seller_team_member product_submission
|
|
36
36
|
seller seller_requirement seller_requirement_submission seller_requirement_status commission_rate
|
|
37
|
-
commission_rule commission_line seller_transfer seller_payout seller_balance payment_split payment_capture_event address
|
|
37
|
+
commission_rule commission_line seller_transfer seller_payout seller_balance payment_split payment_capture_event address address_owner
|
|
38
38
|
channel order_routing_rule product_publication market delivery_method delivery_method_service
|
|
39
39
|
stock_location stock_reservation delivery_rate freight_summary freight_summary_line payment_method
|
|
40
40
|
credit_card store_credit store_credit_event customer_group payment_source digital_asset digital_link
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
# Renders every value list the serializers name (`enum_type_name:`, see
|
|
4
|
+
# {Typelizer::OpenEnums}) into `@spree/core`, once, as both the values and
|
|
5
|
+
# the type — open unless the name is one of `CLOSED_LIST_NAMES`. Each SDK's `Enums.ts` re-exports the type
|
|
6
|
+
# from there instead of carrying its own copy, and the dashboards read the
|
|
7
|
+
# values instead of repeating them by hand.
|
|
8
|
+
#
|
|
9
|
+
# Run by `rake typelizer:generate`; `enum_types_spec.rb` fails when the
|
|
10
|
+
# committed file no longer matches the serializers.
|
|
11
|
+
class EnumTypes
|
|
12
|
+
class ConflictError < StandardError; end
|
|
13
|
+
|
|
14
|
+
HEADER = "// This file is auto-generated from the API serializers by `rake typelizer:generate`. Do not edit directly.\n".freeze
|
|
15
|
+
PATH = 'packages/core/src/enums.generated.ts'.freeze
|
|
16
|
+
LINE_WIDTH = 100
|
|
17
|
+
|
|
18
|
+
# @param properties [Array<Typelizer::Property>] every named enum property, across all serializers
|
|
19
|
+
def initialize(properties = self.class.serializer_properties)
|
|
20
|
+
@properties = properties
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Walks every property rather than Typelizer's own `enum_types`, which
|
|
24
|
+
# keeps one property per name within a serializer and so would hide two
|
|
25
|
+
# attributes of one serializer that disagree.
|
|
26
|
+
#
|
|
27
|
+
# @return [Array<Typelizer::Property>] the named enum properties of every serializer each Typelizer writer emits
|
|
28
|
+
def self.serializer_properties
|
|
29
|
+
Typelizer.configuration.writers.keys
|
|
30
|
+
.flat_map { |writer_name| Typelizer.interfaces(writer_name: writer_name) }
|
|
31
|
+
.flat_map { |interface| named_properties(interface.properties + interface.trait_interfaces.flat_map(&:properties)) }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @param properties [Array<Typelizer::Property>]
|
|
35
|
+
# @return [Array<Typelizer::Property>] those carrying a named list, nested and inline ones included
|
|
36
|
+
def self.named_properties(properties)
|
|
37
|
+
properties.flat_map do |property|
|
|
38
|
+
nested = property.nested_properties.to_a
|
|
39
|
+
nested += property.type.properties if property.type.is_a?(Typelizer::Interface) && property.type.inline?
|
|
40
|
+
|
|
41
|
+
[property, *named_properties(nested)]
|
|
42
|
+
end.select { |property| property.enum && property.enum_type_name }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @return [Hash{String => Array<String>}] built-in values keyed by type name
|
|
46
|
+
# @raise [ConflictError] when two serializers give one type name different values
|
|
47
|
+
def lists
|
|
48
|
+
@lists ||= @properties
|
|
49
|
+
.select(&:enum_type_name)
|
|
50
|
+
.reject { |property| Typelizer::OpenEnums::CLOSED_TYPE_NAMES.include?(property.enum_type_name) }
|
|
51
|
+
.group_by(&:enum_type_name)
|
|
52
|
+
.sort
|
|
53
|
+
.to_h { |name, properties| [name, values_of(name, properties)] }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @return [Array<String>] closed list names no serializer declares any more
|
|
57
|
+
def stale_closed_names
|
|
58
|
+
Typelizer::OpenEnums::CLOSED_LIST_NAMES - lists.keys
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @return [String] the file's contents
|
|
62
|
+
def render
|
|
63
|
+
HEADER + lists.map { |name, values| definition(name, values) }.join + built_in_status
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @param root [Pathname] the monorepo root
|
|
67
|
+
# @return [void]
|
|
68
|
+
# @raise [ConflictError] when `CLOSED_LIST_NAMES` names a list no serializer declares
|
|
69
|
+
def write!(root)
|
|
70
|
+
raise ConflictError, "No serializer names #{stale_closed_names.join(', ')}; remove it from CLOSED_LIST_NAMES." if stale_closed_names.any?
|
|
71
|
+
|
|
72
|
+
File.write(root.join(PATH), render)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @param name [String] a type name, e.g. `ProductStatus`
|
|
76
|
+
# @return [String] the constant holding its values, e.g. `PRODUCT_STATUSES`
|
|
77
|
+
def self.constant_name(name)
|
|
78
|
+
name.underscore.pluralize.upcase
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def values_of(name, properties)
|
|
84
|
+
variants = properties.map { |property| property.enum.map(&:to_s) }.uniq
|
|
85
|
+
return variants.first if variants.one?
|
|
86
|
+
|
|
87
|
+
raise ConflictError, "#{name} is declared with different values: " \
|
|
88
|
+
"#{variants.map { |values| values.join(', ') }.join(' / ')}. " \
|
|
89
|
+
'Give every serializer the same list, or give the lists different names.'
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Every built-in value of every status list, so a surface that styles
|
|
93
|
+
# statuses can be checked for one the server added.
|
|
94
|
+
def built_in_status
|
|
95
|
+
members = lists.keys.grep(/Status\z/).map { |name| " | (typeof #{self.class.constant_name(name)})[number]\n" }
|
|
96
|
+
return '' if members.empty?
|
|
97
|
+
|
|
98
|
+
"\n/** Every built-in value of every status list above. */\nexport type BuiltInStatus =\n#{members.join}"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def definition(name, values)
|
|
102
|
+
constant = self.class.constant_name(name)
|
|
103
|
+
quoted = values.map { |value| "'#{value}'" }
|
|
104
|
+
line = "export const #{constant} = [#{quoted.join(', ')}] as const"
|
|
105
|
+
line = "export const #{constant} = [\n#{quoted.map { |value| " #{value},\n" }.join}] as const" if line.length > LINE_WIDTH
|
|
106
|
+
|
|
107
|
+
if Typelizer::OpenEnums.closed?(name)
|
|
108
|
+
"\n/** Every value of `#{name}`. */\n#{line}\nexport type #{name} = (typeof #{constant})[number]\n"
|
|
109
|
+
else
|
|
110
|
+
type = "export type #{name} = (typeof #{constant})[number] | (string & {})"
|
|
111
|
+
type = "export type #{name} =\n | (typeof #{constant})[number]\n | (string & {})" if type.length > LINE_WIDTH
|
|
112
|
+
|
|
113
|
+
"\n/** The built-in values of `#{name}`. Extensions may add more. */\n#{line}\n#{type}\n"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -106,13 +106,20 @@ module Spree
|
|
|
106
106
|
def attribute_rows(table)
|
|
107
107
|
rows = ['| Attribute | Kind | Predicates |', '|---|---|---|']
|
|
108
108
|
table.attributes.except(*table.aliased_attributes).each do |attribute, kind|
|
|
109
|
-
label =
|
|
109
|
+
label = kind_label(kind)
|
|
110
110
|
predicates = Spree::Api::V3::FilterPredicates::BY_KIND.fetch(kind.is_a?(Hash) ? 'enum' : kind)
|
|
111
111
|
rows << "| `#{attribute}` | #{label} | #{predicates.map { |predicate| "`#{predicate}`" }.join(' ')} |"
|
|
112
112
|
end
|
|
113
113
|
rows
|
|
114
114
|
end
|
|
115
115
|
|
|
116
|
+
def kind_label(kind)
|
|
117
|
+
return KIND_LABELS.fetch(kind) unless kind.is_a?(Hash)
|
|
118
|
+
return "One of the `#{kind['code']}` codes" if kind['code']
|
|
119
|
+
|
|
120
|
+
"One of #{kind['enum'].map { |value| "`#{value}`" }.join(', ')}"
|
|
121
|
+
end
|
|
122
|
+
|
|
116
123
|
def association_rows
|
|
117
124
|
visible = ->(table) { table.attributes.keys - table.aliased_attributes }
|
|
118
125
|
@table.associations.flat_map do |name, associated|
|