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.
Files changed (370) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +0 -17
  3. data/app/controllers/concerns/spree/api/v3/admin/product_membership.rb +10 -0
  4. data/app/controllers/concerns/spree/api/v3/admin/stock_receipt_actions.rb +26 -4
  5. data/app/controllers/concerns/spree/api/v3/admin/subclassed_resource.rb +14 -28
  6. data/app/controllers/concerns/spree/api/v3/admin/validation_details.rb +1 -1
  7. data/app/controllers/concerns/spree/api/v3/cart_resolvable.rb +3 -2
  8. data/app/controllers/concerns/spree/api/v3/channel_resolution.rb +1 -1
  9. data/app/controllers/concerns/spree/api/v3/company_address_writes.rb +3 -1
  10. data/app/controllers/concerns/spree/api/v3/error_handler.rb +48 -2
  11. data/app/controllers/concerns/spree/api/v3/file_uploads.rb +35 -0
  12. data/app/controllers/concerns/spree/api/v3/money_params.rb +52 -0
  13. data/app/controllers/concerns/spree/api/v3/orders/claim_actions.rb +1 -5
  14. data/app/controllers/concerns/spree/api/v3/orders/delivery_actions.rb +6 -6
  15. data/app/controllers/concerns/spree/api/v3/orders/exchange_actions.rb +1 -4
  16. data/app/controllers/concerns/spree/api/v3/orders/fulfillment_actions.rb +1 -5
  17. data/app/controllers/concerns/spree/api/v3/orders/return_actions.rb +1 -4
  18. data/app/controllers/concerns/spree/api/v3/orders/shipping_label_actions.rb +5 -21
  19. data/app/controllers/concerns/spree/api/v3/params_normalizer.rb +5 -0
  20. data/app/controllers/concerns/spree/api/v3/purchase_serialization.rb +26 -0
  21. data/app/controllers/concerns/spree/api/v3/request_params.rb +65 -0
  22. data/app/controllers/concerns/spree/api/v3/strict_money_params.rb +94 -0
  23. data/app/controllers/spree/api/v3/admin/admin_users_controller.rb +10 -1
  24. data/app/controllers/spree/api/v3/admin/allowed_origins_controller.rb +8 -1
  25. data/app/controllers/spree/api/v3/admin/api_keys_controller.rb +15 -7
  26. data/app/controllers/spree/api/v3/admin/base_controller.rb +1 -0
  27. data/app/controllers/spree/api/v3/admin/catalogs/order_minimums_controller.rb +3 -1
  28. data/app/controllers/spree/api/v3/admin/catalogs/quantity_rules_controller.rb +7 -5
  29. data/app/controllers/spree/api/v3/admin/catalogs_controller.rb +60 -33
  30. data/app/controllers/spree/api/v3/admin/categories/products_controller.rb +4 -1
  31. data/app/controllers/spree/api/v3/admin/categories_controller.rb +40 -20
  32. data/app/controllers/spree/api/v3/admin/channels_controller.rb +39 -6
  33. data/app/controllers/spree/api/v3/admin/claim_reasons_controller.rb +5 -1
  34. data/app/controllers/spree/api/v3/admin/collections/products_controller.rb +4 -1
  35. data/app/controllers/spree/api/v3/admin/collections_controller.rb +44 -15
  36. data/app/controllers/spree/api/v3/admin/commission_rates_controller.rb +60 -12
  37. data/app/controllers/spree/api/v3/admin/companies/addresses_controller.rb +11 -0
  38. data/app/controllers/spree/api/v3/admin/companies/memberships_controller.rb +9 -1
  39. data/app/controllers/spree/api/v3/admin/companies/tax_exemption_certificates_controller.rb +19 -18
  40. data/app/controllers/spree/api/v3/admin/companies/tax_identifiers_controller.rb +6 -1
  41. data/app/controllers/spree/api/v3/admin/companies_controller.rb +17 -3
  42. data/app/controllers/spree/api/v3/admin/countries_controller.rb +5 -1
  43. data/app/controllers/spree/api/v3/admin/custom_field_definitions_controller.rb +21 -11
  44. data/app/controllers/spree/api/v3/admin/custom_fields_controller.rb +12 -5
  45. data/app/controllers/spree/api/v3/admin/customer_groups_controller.rb +9 -1
  46. data/app/controllers/spree/api/v3/admin/customers/addresses_controller.rb +12 -7
  47. data/app/controllers/spree/api/v3/admin/customers/store_credits_controller.rb +11 -9
  48. data/app/controllers/spree/api/v3/admin/customers/tax_identifiers_controller.rb +6 -1
  49. data/app/controllers/spree/api/v3/admin/customers_controller.rb +35 -7
  50. data/app/controllers/spree/api/v3/admin/data_requests_controller.rb +8 -0
  51. data/app/controllers/spree/api/v3/admin/delivery_method_rules_controller.rb +1 -1
  52. data/app/controllers/spree/api/v3/admin/delivery_methods/rules_controller.rb +15 -7
  53. data/app/controllers/spree/api/v3/admin/delivery_methods_controller.rb +92 -57
  54. data/app/controllers/spree/api/v3/admin/delivery_profiles/origin_groups_controller.rb +8 -1
  55. data/app/controllers/spree/api/v3/admin/delivery_profiles_controller.rb +13 -1
  56. data/app/controllers/spree/api/v3/admin/delivery_zones_controller.rb +21 -5
  57. data/app/controllers/spree/api/v3/admin/email_templates/drafts_controller.rb +14 -1
  58. data/app/controllers/spree/api/v3/admin/email_templates/previews_controller.rb +4 -0
  59. data/app/controllers/spree/api/v3/admin/email_templates/publications_controller.rb +7 -0
  60. data/app/controllers/spree/api/v3/admin/email_templates/restorations_controller.rb +8 -0
  61. data/app/controllers/spree/api/v3/admin/email_templates/test_emails_controller.rb +4 -0
  62. data/app/controllers/spree/api/v3/admin/exports_controller.rb +23 -6
  63. data/app/controllers/spree/api/v3/admin/files_controller.rb +29 -0
  64. data/app/controllers/spree/api/v3/admin/gift_card_batches_controller.rb +20 -1
  65. data/app/controllers/spree/api/v3/admin/gift_cards_controller.rb +19 -1
  66. data/app/controllers/spree/api/v3/admin/imports_controller.rb +36 -9
  67. data/app/controllers/spree/api/v3/admin/integrations_controller.rb +13 -1
  68. data/app/controllers/spree/api/v3/admin/invitation_acceptances_controller.rb +9 -2
  69. data/app/controllers/spree/api/v3/admin/invitations_controller.rb +8 -1
  70. data/app/controllers/spree/api/v3/admin/locales_controller.rb +1 -1
  71. data/app/controllers/spree/api/v3/admin/markets_controller.rb +30 -9
  72. data/app/controllers/spree/api/v3/admin/me_controller.rb +12 -3
  73. data/app/controllers/spree/api/v3/admin/media_controller.rb +22 -9
  74. data/app/controllers/spree/api/v3/admin/media_library_controller.rb +4 -0
  75. data/app/controllers/spree/api/v3/admin/option_types_controller.rb +24 -7
  76. data/app/controllers/spree/api/v3/admin/order_cancellation_reasons_controller.rb +5 -1
  77. data/app/controllers/spree/api/v3/admin/order_routing_rules_controller.rb +13 -1
  78. data/app/controllers/spree/api/v3/admin/orders/claims_controller.rb +39 -1
  79. data/app/controllers/spree/api/v3/admin/orders/deliveries_controller.rb +19 -1
  80. data/app/controllers/spree/api/v3/admin/orders/discount_codes_controller.rb +5 -1
  81. data/app/controllers/spree/api/v3/admin/orders/discounts_controller.rb +29 -5
  82. data/app/controllers/spree/api/v3/admin/orders/exchanges_controller.rb +36 -1
  83. data/app/controllers/spree/api/v3/admin/orders/fees_controller.rb +22 -1
  84. data/app/controllers/spree/api/v3/admin/orders/fulfillments_controller.rb +66 -7
  85. data/app/controllers/spree/api/v3/admin/orders/gift_cards_controller.rb +6 -2
  86. data/app/controllers/spree/api/v3/admin/orders/items_controller.rb +11 -1
  87. data/app/controllers/spree/api/v3/admin/orders/labels_controller.rb +35 -2
  88. data/app/controllers/spree/api/v3/admin/orders/payments_controller.rb +16 -5
  89. data/app/controllers/spree/api/v3/admin/orders/refunds_controller.rb +6 -0
  90. data/app/controllers/spree/api/v3/admin/orders/returns_controller.rb +37 -1
  91. data/app/controllers/spree/api/v3/admin/orders/store_credits_controller.rb +6 -3
  92. data/app/controllers/spree/api/v3/admin/orders_controller.rb +74 -60
  93. data/app/controllers/spree/api/v3/admin/package_types_controller.rb +30 -5
  94. data/app/controllers/spree/api/v3/admin/password_resets_controller.rb +17 -0
  95. data/app/controllers/spree/api/v3/admin/payment_methods_controller.rb +38 -22
  96. data/app/controllers/spree/api/v3/admin/policies_controller.rb +8 -4
  97. data/app/controllers/spree/api/v3/admin/price_lists_controller.rb +27 -15
  98. data/app/controllers/spree/api/v3/admin/prices_controller.rb +51 -4
  99. data/app/controllers/spree/api/v3/admin/product_types_controller.rb +25 -8
  100. data/app/controllers/spree/api/v3/admin/products/digital_assets_controller.rb +27 -10
  101. data/app/controllers/spree/api/v3/admin/products/variants_controller.rb +9 -14
  102. data/app/controllers/spree/api/v3/admin/products_controller.rb +121 -70
  103. data/app/controllers/spree/api/v3/admin/promotion_actions_controller.rb +11 -2
  104. data/app/controllers/spree/api/v3/admin/promotion_rules_controller.rb +10 -1
  105. data/app/controllers/spree/api/v3/admin/promotions_controller.rb +50 -14
  106. data/app/controllers/spree/api/v3/admin/purchase_orders_controller.rb +54 -7
  107. data/app/controllers/spree/api/v3/admin/refund_reasons_controller.rb +5 -1
  108. data/app/controllers/spree/api/v3/admin/reporting/saved_reports_controller.rb +9 -1
  109. data/app/controllers/spree/api/v3/admin/reporting_controller.rb +34 -0
  110. data/app/controllers/spree/api/v3/admin/resource_controller.rb +1 -0
  111. data/app/controllers/spree/api/v3/admin/return_reasons_controller.rb +5 -1
  112. data/app/controllers/spree/api/v3/admin/roles_controller.rb +13 -1
  113. data/app/controllers/spree/api/v3/admin/seller_payouts_controller.rb +6 -0
  114. data/app/controllers/spree/api/v3/admin/seller_requirement_submissions_controller.rb +15 -0
  115. data/app/controllers/spree/api/v3/admin/seller_requirements_controller.rb +32 -6
  116. data/app/controllers/spree/api/v3/admin/sellers_controller.rb +75 -22
  117. data/app/controllers/spree/api/v3/admin/setup_controller.rb +54 -15
  118. data/app/controllers/spree/api/v3/admin/stock_levels_controller.rb +38 -9
  119. data/app/controllers/spree/api/v3/admin/stock_locations_controller.rb +41 -9
  120. data/app/controllers/spree/api/v3/admin/stock_transfers_controller.rb +48 -7
  121. data/app/controllers/spree/api/v3/admin/store_controller.rb +122 -53
  122. data/app/controllers/spree/api/v3/admin/store_credits_controller.rb +1 -7
  123. data/app/controllers/spree/api/v3/admin/suppliers_controller.rb +16 -6
  124. data/app/controllers/spree/api/v3/admin/tax_categories_controller.rb +7 -4
  125. data/app/controllers/spree/api/v3/admin/tax_rates_controller.rb +21 -3
  126. data/app/controllers/spree/api/v3/admin/tracking_carriers_controller.rb +4 -0
  127. data/app/controllers/spree/api/v3/admin/translations/batches_controller.rb +17 -9
  128. data/app/controllers/spree/api/v3/admin/translations_controller.rb +4 -0
  129. data/app/controllers/spree/api/v3/admin/translations_coverage_controller.rb +5 -0
  130. data/app/controllers/spree/api/v3/admin/updates_controller.rb +39 -0
  131. data/app/controllers/spree/api/v3/admin/webhook_endpoints_controller.rb +23 -1
  132. data/app/controllers/spree/api/v3/base_controller.rb +2 -0
  133. data/app/controllers/spree/api/v3/resource_controller.rb +63 -10
  134. data/app/controllers/spree/api/v3/seller/auth_controller.rb +8 -0
  135. data/app/controllers/spree/api/v3/seller/base_controller.rb +1 -0
  136. data/app/controllers/spree/api/v3/seller/countries_controller.rb +2 -2
  137. data/app/controllers/spree/api/v3/seller/delivery_methods_controller.rb +49 -60
  138. data/app/controllers/spree/api/v3/seller/exports_controller.rb +18 -1
  139. data/app/controllers/spree/api/v3/seller/files_controller.rb +27 -0
  140. data/app/controllers/spree/api/v3/seller/imports_controller.rb +25 -9
  141. data/app/controllers/spree/api/v3/seller/invitation_acceptances_controller.rb +9 -1
  142. data/app/controllers/spree/api/v3/seller/me_controller.rb +14 -3
  143. data/app/controllers/spree/api/v3/seller/onboarding_controller.rb +11 -0
  144. data/app/controllers/spree/api/v3/seller/orders/claims_controller.rb +35 -0
  145. data/app/controllers/spree/api/v3/seller/orders/deliveries_controller.rb +12 -0
  146. data/app/controllers/spree/api/v3/seller/orders/exchanges_controller.rb +33 -0
  147. data/app/controllers/spree/api/v3/seller/orders/fulfillments_controller.rb +28 -2
  148. data/app/controllers/spree/api/v3/seller/orders/labels_controller.rb +22 -1
  149. data/app/controllers/spree/api/v3/seller/orders/notes_controller.rb +8 -1
  150. data/app/controllers/spree/api/v3/seller/orders/returns_controller.rb +32 -0
  151. data/app/controllers/spree/api/v3/seller/orders_controller.rb +35 -14
  152. data/app/controllers/spree/api/v3/seller/package_types_controller.rb +21 -9
  153. data/app/controllers/spree/api/v3/seller/password_resets_controller.rb +10 -0
  154. data/app/controllers/spree/api/v3/seller/policies_controller.rb +12 -4
  155. data/app/controllers/spree/api/v3/seller/products_controller.rb +114 -28
  156. data/app/controllers/spree/api/v3/seller/profile_controller.rb +33 -10
  157. data/app/controllers/spree/api/v3/seller/requirement_submissions_controller.rb +12 -5
  158. data/app/controllers/spree/api/v3/seller/resource_controller.rb +12 -0
  159. data/app/controllers/spree/api/v3/seller/stock_locations_controller.rb +44 -13
  160. data/app/controllers/spree/api/v3/seller/tax_identifiers_controller.rb +10 -1
  161. data/app/controllers/spree/api/v3/seller/team_controller.rb +4 -0
  162. data/app/controllers/spree/api/v3/store/auth_controller.rb +10 -0
  163. data/app/controllers/spree/api/v3/store/carts/discount_codes_controller.rb +8 -1
  164. data/app/controllers/spree/api/v3/store/carts/fulfillments_controller.rb +10 -2
  165. data/app/controllers/spree/api/v3/store/carts/gift_cards_controller.rb +8 -1
  166. data/app/controllers/spree/api/v3/store/carts/items_controller.rb +17 -5
  167. data/app/controllers/spree/api/v3/store/carts/payment_sessions_controller.rb +20 -6
  168. data/app/controllers/spree/api/v3/store/carts/payments_controller.rb +11 -0
  169. data/app/controllers/spree/api/v3/store/carts/po_documents_controller.rb +24 -26
  170. data/app/controllers/spree/api/v3/store/carts/store_credits_controller.rb +7 -1
  171. data/app/controllers/spree/api/v3/store/carts/tax_identifiers_controller.rb +5 -1
  172. data/app/controllers/spree/api/v3/store/carts_controller.rb +56 -47
  173. data/app/controllers/spree/api/v3/store/companies/addresses_controller.rb +12 -4
  174. data/app/controllers/spree/api/v3/store/companies/members_controller.rb +4 -0
  175. data/app/controllers/spree/api/v3/store/companies_controller.rb +5 -1
  176. data/app/controllers/spree/api/v3/store/company_invitations_controller.rb +9 -1
  177. data/app/controllers/spree/api/v3/store/customer/addresses_controller.rb +8 -7
  178. data/app/controllers/spree/api/v3/store/customer/data_requests_controller.rb +5 -0
  179. data/app/controllers/spree/api/v3/store/customer/password_resets_controller.rb +17 -0
  180. data/app/controllers/spree/api/v3/store/customer/payment_setup_sessions_controller.rb +10 -5
  181. data/app/controllers/spree/api/v3/store/customer/tax_identifiers_controller.rb +5 -1
  182. data/app/controllers/spree/api/v3/store/customers_controller.rb +28 -2
  183. data/app/controllers/spree/api/v3/store/newsletter_subscribers_controller.rb +22 -0
  184. data/app/controllers/spree/api/v3/store/orders/claims_controller.rb +11 -2
  185. data/app/controllers/spree/api/v3/store/orders/returns_controller.rb +10 -1
  186. data/app/controllers/spree/api/v3/store/orders_controller.rb +47 -10
  187. data/app/controllers/spree/api/v3/store/products_controller.rb +8 -0
  188. data/app/controllers/spree/api/v3/store/wishlist_items_controller.rb +10 -4
  189. data/app/controllers/spree/api/v3/store/wishlists_controller.rb +12 -4
  190. data/app/request_schemas/spree/api/v3/address_request_schema.rb +27 -0
  191. data/app/request_schemas/spree/api/v3/admin/address_request_schema.rb +13 -0
  192. data/app/request_schemas/spree/api/v3/admin/bulk_tags_request_schema.rb +17 -0
  193. data/app/request_schemas/spree/api/v3/admin/catalog_order_minimum_request_schema.rb +17 -0
  194. data/app/request_schemas/spree/api/v3/admin/email_template_language_request_schema.rb +17 -0
  195. data/app/request_schemas/spree/api/v3/admin/email_template_preview_request_schema.rb +32 -0
  196. data/app/request_schemas/spree/api/v3/admin/price_adjustment_tier_request_schema.rb +21 -0
  197. data/app/request_schemas/spree/api/v3/admin/price_list_price_request_schema.rb +21 -0
  198. data/app/request_schemas/spree/api/v3/admin/price_list_rule_request_schema.rb +19 -0
  199. data/app/request_schemas/spree/api/v3/admin/product_membership_reposition_request_schema.rb +17 -0
  200. data/app/request_schemas/spree/api/v3/admin/promotion_action_calculator_request_schema.rb +18 -0
  201. data/app/request_schemas/spree/api/v3/admin/promotion_action_line_item_request_schema.rb +15 -0
  202. data/app/request_schemas/spree/api/v3/admin/promotion_action_request_schema.rb +19 -0
  203. data/app/request_schemas/spree/api/v3/admin/promotion_rule_request_schema.rb +22 -0
  204. data/app/request_schemas/spree/api/v3/admin/reason_request_schema.rb +14 -0
  205. data/app/request_schemas/spree/api/v3/admin/tax_identifier_request_schema.rb +15 -0
  206. data/app/request_schemas/spree/api/v3/custom_field_value_request_schema.rb +15 -0
  207. data/app/request_schemas/spree/api/v3/file_upload_request_schema.rb +20 -0
  208. data/app/request_schemas/spree/api/v3/media_request_schema.rb +27 -0
  209. data/app/request_schemas/spree/api/v3/price_request_schema.rb +17 -0
  210. data/app/request_schemas/spree/api/v3/stock_level_request_schema.rb +18 -0
  211. data/app/request_schemas/spree/api/v3/store/address_request_schema.rb +29 -0
  212. data/app/request_schemas/spree/api/v3/tax_identifier_request_schema.rb +18 -0
  213. data/app/request_schemas/spree/api/v3/variant_option_request_schema.rb +13 -0
  214. data/app/request_schemas/spree/api/v3/variant_request_schema.rb +52 -0
  215. data/app/serializers/concerns/spree/api/v3/purchase_summary.rb +48 -0
  216. data/app/serializers/spree/api/v3/address_serializer.rb +4 -2
  217. data/app/serializers/spree/api/v3/admin/address_serializer.rb +3 -0
  218. data/app/serializers/spree/api/v3/admin/applied_promotion_serializer.rb +3 -1
  219. data/app/serializers/spree/api/v3/admin/cart_serializer.rb +3 -1
  220. data/app/serializers/spree/api/v3/admin/catalog_order_minimum_serializer.rb +3 -2
  221. data/app/serializers/spree/api/v3/admin/catalog_price_serializer.rb +3 -4
  222. data/app/serializers/spree/api/v3/admin/catalog_price_tier_serializer.rb +4 -3
  223. data/app/serializers/spree/api/v3/admin/channel_serializer.rb +5 -7
  224. data/app/serializers/spree/api/v3/admin/claim_line_item_serializer.rb +7 -0
  225. data/app/serializers/spree/api/v3/admin/claim_serializer.rb +5 -0
  226. data/app/serializers/spree/api/v3/admin/commission_line_serializer.rb +7 -18
  227. data/app/serializers/spree/api/v3/admin/commission_rate_serializer.rb +7 -11
  228. data/app/serializers/spree/api/v3/admin/commission_rule_serializer.rb +0 -2
  229. data/app/serializers/spree/api/v3/admin/country_serializer.rb +4 -0
  230. data/app/serializers/spree/api/v3/admin/customer_serializer.rb +3 -7
  231. data/app/serializers/spree/api/v3/admin/delivery_method_rule_serializer.rb +0 -2
  232. data/app/serializers/spree/api/v3/admin/delivery_method_serializer.rb +14 -10
  233. data/app/serializers/spree/api/v3/admin/delivery_method_service_serializer.rb +9 -1
  234. data/app/serializers/spree/api/v3/admin/delivery_rate_serializer.rb +8 -0
  235. data/app/serializers/spree/api/v3/admin/discount_serializer.rb +3 -1
  236. data/app/serializers/spree/api/v3/admin/exchange_line_item_serializer.rb +5 -0
  237. data/app/serializers/spree/api/v3/admin/exchange_serializer.rb +5 -0
  238. data/app/serializers/spree/api/v3/admin/fee_serializer.rb +3 -1
  239. data/app/serializers/spree/api/v3/admin/file_upload_serializer.rb +11 -0
  240. data/app/serializers/spree/api/v3/admin/file_upload_target_serializer.rb +10 -0
  241. data/app/serializers/spree/api/v3/admin/fulfillment_serializer.rb +13 -11
  242. data/app/serializers/spree/api/v3/admin/gift_card_serializer.rb +3 -3
  243. data/app/serializers/spree/api/v3/admin/import_serializer.rb +2 -2
  244. data/app/serializers/spree/api/v3/admin/integration_serializer.rb +1 -3
  245. data/app/serializers/spree/api/v3/admin/line_item_serializer.rb +12 -12
  246. data/app/serializers/spree/api/v3/admin/locale_serializer.rb +13 -0
  247. data/app/serializers/spree/api/v3/admin/market_serializer.rb +3 -0
  248. data/app/serializers/spree/api/v3/admin/media_serializer.rb +3 -2
  249. data/app/serializers/spree/api/v3/admin/order_group_serializer.rb +2 -0
  250. data/app/serializers/spree/api/v3/admin/order_routing_rule_serializer.rb +1 -3
  251. data/app/serializers/spree/api/v3/admin/order_serializer.rb +33 -33
  252. data/app/serializers/spree/api/v3/admin/payment_method_serializer.rb +1 -4
  253. data/app/serializers/spree/api/v3/admin/payment_serializer.rb +6 -3
  254. data/app/serializers/spree/api/v3/admin/payment_split_serializer.rb +8 -9
  255. data/app/serializers/spree/api/v3/admin/price_adjustment_tier_serializer.rb +3 -6
  256. data/app/serializers/spree/api/v3/admin/price_history_serializer.rb +5 -2
  257. data/app/serializers/spree/api/v3/admin/price_list_serializer.rb +1 -5
  258. data/app/serializers/spree/api/v3/admin/price_rule_serializer.rb +1 -3
  259. data/app/serializers/spree/api/v3/admin/price_serializer.rb +2 -0
  260. data/app/serializers/spree/api/v3/admin/product_serializer.rb +2 -0
  261. data/app/serializers/spree/api/v3/admin/promotion_action_serializer.rb +4 -6
  262. data/app/serializers/spree/api/v3/admin/promotion_rule_serializer.rb +0 -2
  263. data/app/serializers/spree/api/v3/admin/purchase_order_item_serializer.rb +5 -11
  264. data/app/serializers/spree/api/v3/admin/purchase_order_serializer.rb +4 -4
  265. data/app/serializers/spree/api/v3/admin/refund_serializer.rb +7 -3
  266. data/app/serializers/spree/api/v3/admin/reporting_result_serializer.rb +9 -2
  267. data/app/serializers/spree/api/v3/admin/return_line_item_serializer.rb +8 -0
  268. data/app/serializers/spree/api/v3/admin/return_serializer.rb +8 -4
  269. data/app/serializers/spree/api/v3/admin/seller_balance_serializer.rb +15 -10
  270. data/app/serializers/spree/api/v3/admin/seller_payout_serializer.rb +3 -5
  271. data/app/serializers/spree/api/v3/admin/seller_serializer.rb +3 -1
  272. data/app/serializers/spree/api/v3/admin/seller_transfer_serializer.rb +7 -8
  273. data/app/serializers/spree/api/v3/admin/shipping_label_serializer.rb +4 -4
  274. data/app/serializers/spree/api/v3/admin/stock_location_serializer.rb +3 -0
  275. data/app/serializers/spree/api/v3/admin/stock_movement_serializer.rb +2 -6
  276. data/app/serializers/spree/api/v3/admin/store_credit_event_serializer.rb +5 -0
  277. data/app/serializers/spree/api/v3/admin/store_credit_serializer.rb +9 -4
  278. data/app/serializers/spree/api/v3/admin/store_serializer.rb +17 -98
  279. data/app/serializers/spree/api/v3/admin/supplier_serializer.rb +1 -1
  280. data/app/serializers/spree/api/v3/admin/tax_exemption_certificate_serializer.rb +3 -1
  281. data/app/serializers/spree/api/v3/admin/tax_line_serializer.rb +4 -2
  282. data/app/serializers/spree/api/v3/admin/tax_rate_serializer.rb +2 -12
  283. data/app/serializers/spree/api/v3/admin/update_status_serializer.rb +28 -0
  284. data/app/serializers/spree/api/v3/admin/variant_serializer.rb +7 -3
  285. data/app/serializers/spree/api/v3/base_serializer.rb +112 -7
  286. data/app/serializers/spree/api/v3/cart_serializer.rb +11 -29
  287. data/app/serializers/spree/api/v3/claim_line_item_serializer.rb +5 -13
  288. data/app/serializers/spree/api/v3/claim_serializer.rb +2 -3
  289. data/app/serializers/spree/api/v3/country_serializer.rb +2 -1
  290. data/app/serializers/spree/api/v3/currency_serializer.rb +9 -1
  291. data/app/serializers/spree/api/v3/customer_serializer.rb +3 -2
  292. data/app/serializers/spree/api/v3/delivery_rate_serializer.rb +8 -12
  293. data/app/serializers/spree/api/v3/delivery_zone_member_serializer.rb +1 -1
  294. data/app/serializers/spree/api/v3/discount_serializer.rb +4 -1
  295. data/app/serializers/spree/api/v3/exchange_line_item_serializer.rb +2 -8
  296. data/app/serializers/spree/api/v3/exchange_serializer.rb +2 -3
  297. data/app/serializers/spree/api/v3/file_upload_serializer.rb +28 -0
  298. data/app/serializers/spree/api/v3/file_upload_target_serializer.rb +17 -0
  299. data/app/serializers/spree/api/v3/gift_card_batch_serializer.rb +2 -4
  300. data/app/serializers/spree/api/v3/gift_card_serializer.rb +4 -2
  301. data/app/serializers/spree/api/v3/import_serializer.rb +0 -12
  302. data/app/serializers/spree/api/v3/line_item_serializer.rb +15 -5
  303. data/app/serializers/spree/api/v3/locale_serializer.rb +3 -1
  304. data/app/serializers/spree/api/v3/market_serializer.rb +5 -5
  305. data/app/serializers/spree/api/v3/media_serializer.rb +7 -2
  306. data/app/serializers/spree/api/v3/order_group_serializer.rb +12 -4
  307. data/app/serializers/spree/api/v3/order_serializer.rb +5 -23
  308. data/app/serializers/spree/api/v3/payment_session_serializer.rb +2 -4
  309. data/app/serializers/spree/api/v3/price_history_serializer.rb +5 -5
  310. data/app/serializers/spree/api/v3/price_serializer.rb +6 -9
  311. data/app/serializers/spree/api/v3/product_filter_price_range_serializer.rb +10 -4
  312. data/app/serializers/spree/api/v3/product_serializer.rb +3 -3
  313. data/app/serializers/spree/api/v3/refund_serializer.rb +8 -5
  314. data/app/serializers/spree/api/v3/return_line_item_serializer.rb +3 -11
  315. data/app/serializers/spree/api/v3/return_serializer.rb +3 -6
  316. data/app/serializers/spree/api/v3/seller/address_serializer.rb +12 -0
  317. data/app/serializers/spree/api/v3/seller/balance_serializer.rb +15 -10
  318. data/app/serializers/spree/api/v3/seller/claim_line_item_serializer.rb +7 -0
  319. data/app/serializers/spree/api/v3/seller/claim_serializer.rb +5 -0
  320. data/app/serializers/spree/api/v3/seller/country_serializer.rb +19 -0
  321. data/app/serializers/spree/api/v3/seller/delivery_method_rule_serializer.rb +1 -3
  322. data/app/serializers/spree/api/v3/seller/delivery_method_serializer.rb +4 -8
  323. data/app/serializers/spree/api/v3/seller/delivery_rate_serializer.rb +9 -8
  324. data/app/serializers/spree/api/v3/seller/exchange_line_item_serializer.rb +5 -0
  325. data/app/serializers/spree/api/v3/seller/exchange_serializer.rb +5 -0
  326. data/app/serializers/spree/api/v3/seller/file_upload_serializer.rb +11 -0
  327. data/app/serializers/spree/api/v3/seller/file_upload_target_serializer.rb +10 -0
  328. data/app/serializers/spree/api/v3/seller/import_serializer.rb +2 -2
  329. data/app/serializers/spree/api/v3/seller/media_serializer.rb +2 -5
  330. data/app/serializers/spree/api/v3/seller/order_line_item_serializer.rb +4 -3
  331. data/app/serializers/spree/api/v3/seller/order_serializer.rb +16 -16
  332. data/app/serializers/spree/api/v3/seller/payment_split_serializer.rb +8 -9
  333. data/app/serializers/spree/api/v3/seller/payout_serializer.rb +2 -4
  334. data/app/serializers/spree/api/v3/seller/price_history_serializer.rb +11 -0
  335. data/app/serializers/spree/api/v3/seller/price_serializer.rb +11 -0
  336. data/app/serializers/spree/api/v3/seller/product_serializer.rb +2 -0
  337. data/app/serializers/spree/api/v3/seller/profile_serializer.rb +7 -7
  338. data/app/serializers/spree/api/v3/seller/return_line_item_serializer.rb +8 -0
  339. data/app/serializers/spree/api/v3/seller/return_serializer.rb +8 -5
  340. data/app/serializers/spree/api/v3/seller/state_serializer.rb +10 -0
  341. data/app/serializers/spree/api/v3/seller/stock_location_serializer.rb +3 -0
  342. data/app/serializers/spree/api/v3/seller/transfer_serializer.rb +6 -7
  343. data/app/serializers/spree/api/v3/seller/variant_serializer.rb +8 -4
  344. data/app/serializers/spree/api/v3/stock_location_serializer.rb +8 -1
  345. data/app/serializers/spree/api/v3/store_credit_event_serializer.rb +1 -3
  346. data/app/serializers/spree/api/v3/store_credit_serializer.rb +3 -5
  347. data/app/serializers/spree/api/v3/tax_line_serializer.rb +2 -4
  348. data/app/serializers/spree/api/v3/variant_serializer.rb +3 -3
  349. data/app/services/spree/api/v3/filter_predicates.rb +29 -0
  350. data/app/services/spree/api/v3/filter_table.rb +337 -0
  351. data/app/services/spree/api/v3/filters_aggregator.rb +2 -2
  352. data/app/services/spree/api/v3/request_schema.rb +430 -0
  353. data/app/services/spree/webhooks/deliver_webhook.rb +7 -3
  354. data/config/initializers/typelizer.rb +1 -1
  355. data/config/routes.rb +5 -3
  356. data/lib/spree/api/configuration.rb +5 -0
  357. data/lib/spree/api/dependencies.rb +7 -6
  358. data/lib/spree/api/middleware/request_size_limit.rb +24 -3
  359. data/lib/spree/api/openapi/filter_documentation.rb +136 -0
  360. data/lib/spree/api/openapi/schema_helper.rb +126 -80
  361. data/lib/spree/api/preference_families.rb +46 -0
  362. data/lib/spree/api/preference_types.rb +138 -0
  363. data/lib/spree/api/typelizer_generation.rb +4 -0
  364. data/lib/tasks/filters.rake +12 -0
  365. data/lib/typelizer/open_enums.rb +10 -0
  366. metadata +60 -10
  367. data/app/controllers/concerns/spree/api/v3/address_params.rb +0 -17
  368. data/app/controllers/concerns/spree/api/v3/direct_uploads.rb +0 -35
  369. data/app/controllers/spree/api/v3/admin/direct_uploads_controller.rb +0 -54
  370. data/app/controllers/spree/api/v3/seller/direct_uploads_controller.rb +0 -21
@@ -0,0 +1,94 @@
1
+ module Spree
2
+ module Api
3
+ module V3
4
+ # Admin and Seller writes take money and rates as canonical decimal
5
+ # strings only ("19.99", "0.23"): a JSON number, localized text or more
6
+ # decimals than the field holds is answered with `invalid_money_format`
7
+ # before anything is written. A money field checks its currency's decimals
8
+ # when the payload names the currency beside it, and four otherwise; unit
9
+ # prices always allow four. Store API writes carry no amounts and are not
10
+ # checked here.
11
+ module StrictMoneyParams
12
+ extend ActiveSupport::Concern
13
+
14
+ MONEY_KEYS = %w[
15
+ amount compare_at_amount cost cost_price price unit_cost refund_amount settled_amount
16
+ minimum_payout_amount min_amount max_amount markup_flat
17
+ amount_min amount_max first_item additional_item minimal_amount normal_amount discount_amount
18
+ base_amount minimum_item_total maximum_item_total default_minimum_payout_amount
19
+ preferred_default_minimum_payout_amount
20
+ ].freeze
21
+
22
+ UNIT_PRICE_KEYS = %w[price compare_at_amount cost_price unit_cost].freeze
23
+
24
+ RATE_KEYS = %w[
25
+ rate rate_percent percent flat_percent base_percent markup_percent percentage
26
+ price_adjustment_percentage commission_tax_rate default_commission_tax_rate
27
+ preferred_default_commission_tax_rate
28
+ ].freeze
29
+
30
+ # Values the merchant or a provider owns, stored as sent.
31
+ OPAQUE_KEYS = %w[metadata custom_fields external_data].freeze
32
+
33
+ # Preferences are checked against their declared types when assigned
34
+ # (Spree::Preferences::Preferable#assign_preferences), so a money
35
+ # preference is recognized by its type rather than its name.
36
+ TYPED_KEYS = %w[preferences calculator_preferences].freeze
37
+
38
+ included do
39
+ before_action :refuse_noncanonical_decimals, if: -> { request.post? || request.patch? || request.put? }
40
+ end
41
+
42
+ private
43
+
44
+ def refuse_noncanonical_decimals
45
+ check_decimals(request.request_parameters, parent: nil, currency: nil)
46
+ end
47
+
48
+ def check_decimals(node, parent:, currency:)
49
+ case node
50
+ when Hash
51
+ currency = node['currency'].presence || currency
52
+ node.each do |key, value|
53
+ next if OPAQUE_KEYS.include?(key) || TYPED_KEYS.include?(key)
54
+
55
+ if scalar?(value) && MONEY_KEYS.include?(key)
56
+ check_money(key, value, currency, UNIT_PRICE_KEYS.include?(key) || (key == 'amount' && parent == 'prices'))
57
+ elsif scalar?(value) && RATE_KEYS.include?(key)
58
+ check_rate(key, value)
59
+ else
60
+ check_decimals(value, parent: key, currency: currency)
61
+ end
62
+ end
63
+ when Array
64
+ node.each { |item| check_decimals(item, parent: parent, currency: currency) }
65
+ end
66
+ end
67
+
68
+ def check_money(key, value, currency, unit_price)
69
+ return if blank_value?(value)
70
+
71
+ Spree::Money::Rounding.parse_canonical(value, currency.presence, unit_price: unit_price)
72
+ rescue Spree::Money::InvalidFormat => error
73
+ raise Spree::Money::InvalidFormat.new(error.message, field: key.to_sym)
74
+ end
75
+
76
+ def check_rate(key, value)
77
+ return if blank_value?(value)
78
+
79
+ Spree::Money::Rounding.parse_canonical_decimal(value)
80
+ rescue Spree::Money::InvalidFormat => error
81
+ raise Spree::Money::InvalidFormat.new(error.message, field: key.to_sym)
82
+ end
83
+
84
+ def scalar?(value)
85
+ !value.is_a?(Hash) && !value.is_a?(Array)
86
+ end
87
+
88
+ def blank_value?(value)
89
+ value.nil? || (value.is_a?(String) && value.strip.empty?)
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -14,6 +14,15 @@ module Spree
14
14
  # grantable separately from store configuration (6.0-admin-rbac.md).
15
15
  scoped_resource :staff
16
16
 
17
+ request_params :admin_user do |body|
18
+ body.attribute :first_name, :string
19
+ body.attribute :last_name, :string
20
+ # Applied through `apply_role_ids`, scoped to the current store.
21
+ body.attribute :role_ids, :array, of: :id,
22
+ permit: false,
23
+ description: "Role IDs of the current store the user should hold. Replaces the user's roles on this store; an empty list removes them all."
24
+ end
25
+
17
26
  # DELETE /api/v3/admin/admin_users/:id
18
27
  # Removes role assignments for the current store rather than deleting
19
28
  # the account globally. The user keeps access to any other stores.
@@ -79,7 +88,7 @@ module Spree
79
88
  private
80
89
 
81
90
  def identity_params
82
- params.permit(:first_name, :last_name)
91
+ params.permit(*declared_permitted_attributes)
83
92
  end
84
93
 
85
94
  def role_ids_param
@@ -5,6 +5,13 @@ module Spree
5
5
  class AllowedOriginsController < ResourceController
6
6
  scoped_resource :settings
7
7
 
8
+ request_params :allowed_origin do |body|
9
+ body.attribute :origin, :string,
10
+ required: true, on: :create,
11
+ example: 'https://admin.example.com',
12
+ description: 'Origin to allow in admin CORS preflight checks: a bare `scheme://host[:port]` (no path, query or fragment) using `http` or `https`.'
13
+ end
14
+
8
15
  protected
9
16
 
10
17
  def model_class
@@ -16,7 +23,7 @@ module Spree
16
23
  end
17
24
 
18
25
  def permitted_params
19
- params.permit(*model_additional_permitted_attributes, :origin)
26
+ params.permit(*permitted_attributes)
20
27
  end
21
28
  end
22
29
  end
@@ -14,6 +14,20 @@ module Spree
14
14
  # `read_api_keys` — any key can describe itself.
15
15
  skip_scope_check! only: :current
16
16
 
17
+ # `key_type`, `scopes` and `channel_id` are create-only (immutability
18
+ # lives on Spree::ApiKey), so a rename returns 200 rather than 422.
19
+ request_params :api_key do |body|
20
+ body.attribute :name, :string, required: true
21
+ body.attribute :key_type, :string, required: true, only: :create, choices: Spree::ApiKey::KEY_TYPES
22
+ body.attribute :scopes, :array, of: :string,
23
+ only: :create,
24
+ example: %w[read_orders write_products],
25
+ description: 'Required for secret keys. You can only grant scopes you hold yourself. Fixed once created: to change them, create a new key and revoke the old one.'
26
+ body.attribute :channel_id, :id,
27
+ only: :create,
28
+ description: 'Binds a publishable key to one channel of the store (`ch_...`), so it rejects requests for other channels. Fixed once created; omit it for a store-wide key.'
29
+ end
30
+
17
31
  # POST /api/v3/admin/api_keys
18
32
  # Prevents scope amplification for BOTH principals: a key minted via a
19
33
  # secret API key can only carry scopes that key already holds, and a
@@ -94,16 +108,10 @@ module Spree
94
108
  end
95
109
  end
96
110
 
97
- # `key_type`, `scopes`, and `channel_id` are create-only (immutability
98
- # lives on Spree::ApiKey); update is limited to the human-facing `name`.
99
- # Stripping them here keeps them out of mass assignment so a rename
100
- # returns 200 rather than 422.
101
111
  # No extension union: an API key's scopes and type are the authorization
102
112
  # surface itself, not extensible resource data.
103
113
  def permitted_params
104
- return params.permit(:name) if action_name == 'update'
105
-
106
- params.permit(:name, :key_type, :channel_id, scopes: [])
114
+ params.permit(*declared_permitted_attributes)
107
115
  end
108
116
 
109
117
  private
@@ -12,6 +12,7 @@ module Spree
12
12
  before_action :authenticate_admin!
13
13
 
14
14
  include Spree::Api::V3::ScopedAuthorization
15
+ include Spree::Api::V3::StrictMoneyParams
15
16
  include Spree::Api::V3::Admin::ValidationDetails
16
17
  include Spree::Api::V3::Admin::EmbedPermissions
17
18
  end
@@ -9,6 +9,8 @@ module Spree
9
9
  class OrderMinimumsController < BaseController
10
10
  before_action :authorize_parent_access!
11
11
 
12
+ request_params('CatalogOrderMinimumParams') { |body| body.include_attributes Spree::Api::V3::Admin::CatalogOrderMinimumRequestSchema }
13
+
12
14
  protected
13
15
 
14
16
  def model_class
@@ -24,7 +26,7 @@ module Spree
24
26
  end
25
27
 
26
28
  def permitted_params
27
- params.permit(:currency, :amount)
29
+ params.permit(*declared_permitted_attributes)
28
30
  end
29
31
  end
30
32
  end
@@ -20,12 +20,14 @@ module Spree
20
20
  class QuantityRulesController < BaseController
21
21
  before_action :authorize_parent_access!
22
22
 
23
+ request_params 'CatalogProductTermsParams', action: :upsert do |body|
24
+ body.attribute :terms, :hash,
25
+ required: true,
26
+ example: { 'prod_abc123' => { minimum_order_quantity: 48, order_multiple: 24 } },
27
+ description: 'Quantity terms keyed by product: `{ minimum_order_quantity, order_multiple }`, each a whole number or null. A product whose pair is both null has its terms cleared; a product not yet in the assortment is added.'
28
+ end
29
+
23
30
  # PUT /api/v3/admin/catalogs/:catalog_id/quantity_rules
24
- #
25
- # { terms: { "prod_abc": { minimum_order_quantity: 48,
26
- # order_multiple: 24 } } }
27
- #
28
- # A product whose pair is both null has its terms cleared.
29
31
  def upsert
30
32
  authorize! :update, @catalog
31
33
 
@@ -6,12 +6,70 @@ module Spree
6
6
  # through assignments. Merchandising data, so it answers to the
7
7
  # products scopes.
8
8
  class CatalogsController < ResourceController
9
+ ASSIGNMENT = Spree::Api::V3::RequestSchema.shape('CatalogAssignmentParams') do |schema|
10
+ schema.attribute :assignable_type, :string,
11
+ required: true,
12
+ choices: %w[customer_group company],
13
+ example: 'company',
14
+ description: 'Buyer audiences only. A company assignment covers its subtree.'
15
+ schema.attribute :assignable_id, :id, required: true, example: 'comp_86Rf07xd4z'
16
+ end
17
+
9
18
  scoped_resource :products
10
19
 
11
20
  before_action :set_resource,
12
21
  only: [:show, :update, :destroy, :assign, :import_products,
13
22
  :activate, :deactivate]
14
23
 
24
+ request_params :catalog do |body|
25
+ body.attribute :name, :string, required: true, on: :create, example: 'VIP Assortment'
26
+ body.attribute :description, :string,
27
+ nullable: true,
28
+ description: 'Internal note on what the agreement is, never shown to shoppers.'
29
+ body.attribute :active, :boolean, example: true
30
+ body.attribute :position, :integer
31
+ body.attribute :minimum_order_quantity, :integer,
32
+ nullable: true,
33
+ description: "The catalog-wide quantity terms, between a variant's own rule and a per-variant override. Null leaves the field to the variant's own rule."
34
+ body.attribute :order_multiple, :integer,
35
+ nullable: true,
36
+ description: "The catalog-wide quantity terms, between a variant's own rule and a per-variant override. Null leaves the field to the variant's own rule."
37
+ body.attribute :metadata, :hash
38
+ # Small bounded sets, saved with the catalog so the whole
39
+ # agreement lands in one transaction. Per-product terms stay their
40
+ # own endpoint: an agreement may name thousands of them.
41
+ body.attribute :assignments, :array, of: ASSIGNMENT,
42
+ description: 'The whole audience. An entry left out is withdrawn; omitting the key leaves the audience alone.'
43
+ body.attribute :order_minimums, :array, of: Spree::Api::V3::Admin::CatalogOrderMinimumRequestSchema,
44
+ description: 'The whole order-minimum set. A currency left out has its minimum lifted; omitting the key leaves them alone.'
45
+ body.attribute :price_list, :object,
46
+ nullable: true,
47
+ as: 'CatalogPriceListParams',
48
+ description: 'The price list this catalog prices through, written inline: an object creates the owned list or updates it. Null deletes the list (a soft delete). Omit the key, or send `{}`, to leave the pricing alone. A catalog with an empty assortment prices without hiding anything; curate or import products to make it restrictive.' do |price_list|
49
+ price_list.attribute :name, :string
50
+ price_list.attribute :description, :string, nullable: true
51
+ price_list.attribute :status, :string
52
+ price_list.attribute :match_policy, :string
53
+ price_list.attribute :starts_at, :datetime, nullable: true
54
+ price_list.attribute :ends_at, :datetime, nullable: true
55
+ price_list.attribute :price_adjustment_percentage, :decimal,
56
+ nullable: true,
57
+ example: '-15.0',
58
+ description: 'Signed: negative discounts off base prices, positive marks up.'
59
+ price_list.attribute :adjust_compare_at, :boolean
60
+ # Audience rules on an owned list are inert, since the catalog
61
+ # assignment already decided the audience.
62
+ price_list.attribute :rules, :array, of: Spree::Api::V3::Admin::PriceListRuleRequestSchema,
63
+ description: "Contextual rules, in practice a `volume_rule`. Audience rules are left as they are, and an empty list clears the contextual rules."
64
+ price_list.attribute :prices, :array, of: Spree::Api::V3::Admin::PriceListPriceRequestSchema,
65
+ description: 'Explicit per-variant amounts. An empty list clears them, which is what switching to a percentage sends.'
66
+ price_list.attribute :price_adjustment_tiers, :array, of: Spree::Api::V3::Admin::PriceAdjustmentTierRequestSchema,
67
+ description: 'Quantity bands on the percentage. The payload is the whole ladder, so an empty list clears it.'
68
+ end
69
+ end
70
+
71
+ request_params('CatalogAssignParams', action: :assign) { |body| body.include_attributes ASSIGNMENT }
72
+
15
73
  # POST /api/v3/admin/catalogs/:id/import_products — copies the
16
74
  # attached price list's products into the assortment. Explicit by
17
75
  # design: an empty assortment is a pricing-only overlay, so making
@@ -30,7 +88,7 @@ module Spree
30
88
  render json: { added_count: @resource.import_products_from_price_list }
31
89
  end
32
90
 
33
- # POST /api/v3/admin/catalogs/:id/assign — { assignable_type, assignable_id }
91
+ # POST /api/v3/admin/catalogs/:id/assign
34
92
  def assign
35
93
  authorize! :update, @resource
36
94
 
@@ -102,38 +160,7 @@ module Spree
102
160
  # as `null` detaches the list the catalog owns; omitting the key
103
161
  # leaves it alone.
104
162
  def permitted_params
105
- permitted = params.permit(*model_additional_permitted_attributes,
106
- :name, :description, :active, :position,
107
- :minimum_order_quantity, :order_multiple,
108
- metadata: {},
109
- # Small bounded sets, saved with the
110
- # catalog so the whole agreement lands
111
- # in one transaction. Per-product terms
112
- # stay their own endpoint — an
113
- # agreement may name thousands of them.
114
- assignments: [:assignable_type, :assignable_id],
115
- order_minimums: [:currency, :amount],
116
- price_list: [
117
- :name, :description, :status, :match_policy,
118
- :starts_at, :ends_at,
119
- :price_adjustment_percentage, :adjust_compare_at,
120
- # Contextual rules only in practice — a
121
- # VolumeRule is what turns a percentage
122
- # into automatic volume pricing. Audience
123
- # rules on an owned list are inert, since
124
- # the catalog assignment already decided
125
- # the audience.
126
- { rules: [:id, :type, { preferences: {} }] },
127
- # An empty array clears the hand-entered
128
- # amounts — what switching to a
129
- # percentage sends.
130
- { prices: [:id, :variant_id, :currency, :min_quantity,
131
- :amount, :compare_at_amount] },
132
- # Quantity bands on the percentage. The
133
- # payload is the whole ladder, so an
134
- # empty array clears it.
135
- { price_adjustment_tiers: [:min_quantity, :percentage] }
136
- ])
163
+ permitted = params.permit(*permitted_attributes)
137
164
  # `permit` drops an explicit null, but detaching has to be
138
165
  # distinguishable from saying nothing.
139
166
  permitted[:price_list] = nil if params.key?(:price_list) && params[:price_list].nil?
@@ -15,8 +15,11 @@ module Spree
15
15
 
16
16
  before_action :set_product, only: [:reposition]
17
17
 
18
+ request_params 'ProductMembershipRepositionParams', action: :reposition do |body|
19
+ body.include_attributes Spree::Api::V3::Admin::ProductMembershipRepositionRequestSchema
20
+ end
21
+
18
22
  # PATCH /api/v3/admin/categories/:category_id/products/:id/reposition
19
- # Body: { new_position: 0 } — 0-based index among the category's products.
20
23
  # @product is already constrained to the category's scope, so a
21
24
  # classification always exists.
22
25
  def reposition
@@ -11,8 +11,46 @@ module Spree
11
11
  class CategoriesController < ResourceController
12
12
  scoped_resource :categories
13
13
 
14
+ # Category-half attributes only. The collection-bound fields
15
+ # (automatic, sort_order, rules) belong to Spree::Collection, and
16
+ # taxonomy_id is gone with Taxonomy.
17
+ request_params :category do |body|
18
+ body.external_references
19
+ body.attribute :name, :string, required: true, on: :create, example: 'Shirts'
20
+ # Resolved within scope by +permitted_params+, so a parent from
21
+ # another store or an automatic taxon can't be targeted.
22
+ body.attribute :parent_id, :id,
23
+ nullable: true,
24
+ permit: false,
25
+ example: 'ctg_abc123',
26
+ description: 'The parent category. Omitted or null, a new category goes to the top level and an existing one keeps its parent: moving one to the top level is the reposition endpoint.'
27
+ body.attribute :description, :string,
28
+ description: 'Rich text HTML. Reads come back as this (plain text) plus `description_html`.'
29
+ body.attribute :permalink, :string
30
+ body.attribute :meta_title, :string
31
+ body.attribute :meta_description, :string
32
+ body.attribute :meta_keywords, :string
33
+ body.attribute :image_signed_id, :string,
34
+ nullable: true,
35
+ description: 'A `signed_id` from `files.upload()` for the landscape image, or null to remove it.'
36
+ body.attribute :square_image_signed_id, :string,
37
+ nullable: true,
38
+ description: 'A `signed_id` from `files.upload()` for the square image, or null to remove it.'
39
+ body.attribute :custom_fields, :array, of: Spree::Api::V3::CustomFieldValueRequestSchema,
40
+ description: 'Custom field values, each validated against its definition.'
41
+ end
42
+
43
+ request_params 'CategoryRepositionParams', action: :reposition do |body|
44
+ body.attribute :new_parent_id, :id,
45
+ nullable: true,
46
+ description: 'The new parent. Omit or null to move the category to the top level.'
47
+ body.attribute :new_position, :integer,
48
+ required: true,
49
+ example: 0,
50
+ description: "0-based index among the new parent's children."
51
+ end
52
+
14
53
  # PATCH /api/v3/admin/categories/:id/reposition
15
- # Body: { new_parent_id: 'ctg_…' (omit for top level), new_position: 0 }
16
54
  # Moves the category to a new parent (or the top level) and/or index.
17
55
  def reposition
18
56
  category = find_resource
@@ -59,26 +97,8 @@ module Spree
59
97
  super.manual
60
98
  end
61
99
 
62
- # Category-half attributes only. Deliberately excludes the
63
- # collection-bound fields (automatic, sort_order, rules_match_policy,
64
- # taxon_rules) and taxonomy_id — those belong to Spree::Collection
65
- # (6.0) and Taxonomy is being dropped. A prefixed parent_id resolves
66
- # within scope (so a parent from another store or an automatic taxon
67
- # can't be targeted).
68
100
  def permitted_params
69
- permitted = params.permit(
70
- *model_additional_permitted_attributes,
71
- :name, :description, :permalink,
72
- :meta_title, :meta_description, :meta_keywords,
73
- :image, :square_image,
74
- # Inline custom field values keyed by definition id. The model
75
- # setter (Spree::HasCustomFields#custom_fields=) validates each entry
76
- # against its definition. `value` is permitted as a scalar AND as
77
- # `value: []` / `value: {}` so JSON custom_fields round-trip whether
78
- # the parsed payload is an array or an object, while
79
- # text/number/boolean ship scalars.
80
- custom_fields: [:id, :custom_field_definition_id, :value, { value: [] }, { value: {} }]
81
- )
101
+ permitted = params.permit(*permitted_attributes)
82
102
  permitted[:parent] = scope.find_by_prefix_id!(params[:parent_id]) if params[:parent_id].present?
83
103
  permitted
84
104
  end
@@ -5,8 +5,45 @@ module Spree
5
5
  class ChannelsController < ResourceController
6
6
  scoped_resource :settings
7
7
 
8
+ request_params :channel do |body|
9
+ body.attribute :name, :string, required: true, on: :create, example: 'Point of Sale'
10
+ body.attribute :code, :string,
11
+ example: 'pos',
12
+ description: 'URL-safe slug, derived from `name` when blank (`Point of Sale` becomes `point-of-sale`).'
13
+ body.attribute :active, :boolean
14
+ body.attribute :default, :boolean
15
+ body.attribute :order_routing_strategy, :string,
16
+ nullable: true,
17
+ description: 'Order routing strategy shorthand (built-in: `rules`). Null inherits the store setting.'
18
+ body.attribute :storefront_access, :string,
19
+ nullable: true,
20
+ choices: Spree::Channel::Gating::STOREFRONT_ACCESS,
21
+ description: 'What anonymous visitors can see. Null inherits the store setting.'
22
+ body.attribute :guest_checkout, :boolean,
23
+ nullable: true,
24
+ description: 'Whether guests can check out without an account. Null inherits the store setting.'
25
+ body.attribute :default_catalog_id, :id,
26
+ nullable: true,
27
+ description: 'Catalog (`cat_...`) shown to shoppers no company or customer group catalog covers. Null means every product published on the channel.'
28
+ body.attribute :stock_location_ids, :array, of: :id,
29
+ description: 'Stock locations (`sloc_...`) that fulfill this channel. Replaces the whole set; an empty list means every location of the store.'
30
+ end
31
+
32
+ request_params 'ChannelAddProductsParams', action: :add_products do |body|
33
+ body.attribute :product_ids, :array, of: :id, required: true
34
+ body.attribute :published_at, :datetime,
35
+ nullable: true,
36
+ description: 'When the publications go live. Null means immediately.'
37
+ body.attribute :unpublished_at, :datetime,
38
+ nullable: true,
39
+ description: 'When the publications come down. Null means never.'
40
+ end
41
+
42
+ request_params 'ChannelRemoveProductsParams', action: :remove_products do |body|
43
+ body.attribute :product_ids, :array, of: :id, required: true
44
+ end
45
+
8
46
  # POST /api/v3/admin/channels/:id/add_products
9
- # Body: { product_ids: [...], published_at: nil, unpublished_at: nil }
10
47
  def add_products
11
48
  channel = find_resource
12
49
  authorize! :update, channel
@@ -20,7 +57,6 @@ module Spree
20
57
  end
21
58
 
22
59
  # POST /api/v3/admin/channels/:id/remove_products
23
- # Body: { product_ids: [...] }
24
60
  def remove_products
25
61
  channel = find_resource
26
62
  authorize! :update, channel
@@ -61,10 +97,7 @@ module Spree
61
97
  end
62
98
 
63
99
  def permitted_params
64
- params.permit(*model_additional_permitted_attributes, :name, :code, :active, :default, :preferred_order_routing_strategy,
65
- :preferred_storefront_access, :preferred_guest_checkout,
66
- :default_catalog_id,
67
- stock_location_ids: [])
100
+ params.permit(*permitted_attributes)
68
101
  end
69
102
 
70
103
  # `stock_location_ids` replaces the channel's fulfillment-origin
@@ -5,6 +5,10 @@ module Spree
5
5
  class ClaimReasonsController < ResourceController
6
6
  scoped_resource :settings
7
7
 
8
+ request_params :reason do |body|
9
+ body.include_attributes Spree::Api::V3::Admin::ReasonRequestSchema
10
+ end
11
+
8
12
  protected
9
13
 
10
14
  def model_class
@@ -16,7 +20,7 @@ module Spree
16
20
  end
17
21
 
18
22
  def permitted_params
19
- params.permit(*model_additional_permitted_attributes, :name, :active)
23
+ params.permit(*permitted_attributes)
20
24
  end
21
25
  end
22
26
  end
@@ -17,8 +17,11 @@ module Spree
17
17
  before_action :ensure_manual_collection, only: [:create, :destroy, :reposition]
18
18
  before_action :set_product, only: [:reposition]
19
19
 
20
+ request_params 'ProductMembershipRepositionParams', action: :reposition do |body|
21
+ body.include_attributes Spree::Api::V3::Admin::ProductMembershipRepositionRequestSchema
22
+ end
23
+
20
24
  # PATCH /api/v3/admin/collections/:collection_id/products/:id/reposition
21
- # Body: { new_position: 0 } — 0-based index among the collection's products.
22
25
  # @product is already constrained to the collection's scope, so a
23
26
  # ProductCollection always exists.
24
27
  def reposition
@@ -10,6 +10,47 @@ module Spree
10
10
  class CollectionsController < ResourceController
11
11
  scoped_resource :collections
12
12
 
13
+ request_params :collection do |body|
14
+ body.attribute :name, :string, required: true, on: :create, example: 'On Sale'
15
+ body.attribute :description, :string,
16
+ description: 'Rich text HTML. Reads come back as this (plain text) plus `description_html`.'
17
+ body.attribute :permalink, :string
18
+ body.attribute :position, :integer,
19
+ description: "1-based position among the store's collections; the server shifts its siblings. The nested products reposition endpoints, unlike this, take 0-based indexes."
20
+ body.attribute :meta_title, :string
21
+ body.attribute :meta_description, :string
22
+ body.attribute :meta_keywords, :string
23
+ body.attribute :image_signed_id, :string,
24
+ nullable: true,
25
+ description: 'A `signed_id` from `files.upload()` for the landscape image, or null to remove it.'
26
+ body.attribute :square_image_signed_id, :string,
27
+ nullable: true,
28
+ description: 'A `signed_id` from `files.upload()` for the square image, or null to remove it.'
29
+ body.attribute :automatic, :boolean,
30
+ description: 'When true, membership is materialized from `rules` instead of curated by hand.'
31
+ body.attribute :rules_match_policy, :string,
32
+ choices: Spree::Collection::RULES_MATCH_POLICIES,
33
+ description: 'Whether a product must match all rules or any of them. Defaults to `all`.'
34
+ body.attribute :sort_order, :string,
35
+ choices: Spree::Collection::SORT_ORDERS,
36
+ description: "Default product sort for the storefront listing; a shopper's own sort wins. Defaults to `manual`."
37
+ # Applied by the model's sync setter (Spree::Collection#rules=).
38
+ body.attribute :rules, :array,
39
+ as: 'CollectionRuleParams',
40
+ description: 'The complete desired rule set. Entries with an `id` update, entries without one are created, and existing rules left out are removed.' do |rule|
41
+ rule.attribute :id, :id, example: 'crule_abc123', description: 'Omit to create a new rule.'
42
+ rule.attribute :type, :string,
43
+ example: 'tag',
44
+ description: 'Wire shorthand for the rule kind, from the collection rule types endpoint.'
45
+ rule.attribute :value, :string, example: 'summer'
46
+ rule.attribute :match_policy, :string,
47
+ choices: Spree::CollectionRule::MATCH_POLICIES,
48
+ example: 'contains'
49
+ end
50
+ body.attribute :custom_fields, :array, of: Spree::Api::V3::CustomFieldValueRequestSchema,
51
+ description: 'Custom field values, each validated against its definition.'
52
+ end
53
+
13
54
  protected
14
55
 
15
56
  def model_class
@@ -32,22 +73,10 @@ module Spree
32
73
  super.ordered
33
74
  end
34
75
 
35
- # Flat params. +rules+ is applied by the model's sync setter
36
- # (Spree::Collection#rules=): the full desired rule set, prefixed
37
- # +crule_+ ids update, missing ids build, omitted rules are removed —
38
- # so normalize_params is deliberately NOT called (that would rewrite
39
- # +rules+ to +rules_attributes+ and route past the setter).
76
+ # normalize_params is deliberately NOT called: it would rewrite
77
+ # +rules+ to +rules_attributes+ and route past the sync setter.
40
78
  def permitted_params
41
- params.permit(
42
- :name, :description, :permalink, :position,
43
- :meta_title, :meta_description, :meta_keywords,
44
- :image, :square_image,
45
- :automatic, :rules_match_policy, :sort_order,
46
- rules: [:id, :type, :value, :match_policy],
47
- # Inline custom field values keyed by definition id (see
48
- # CategoriesController#permitted_params for the value shapes).
49
- custom_fields: [:id, :custom_field_definition_id, :value, { value: [] }, { value: {} }]
50
- )
79
+ params.permit(*permitted_attributes)
51
80
  end
52
81
  end
53
82
  end