spree_api 6.0.0.beta4 → 6.0.0.rc1

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 (342) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +4 -31
  3. data/app/controllers/concerns/spree/api/v3/admin/email_template_lookup.rb +139 -0
  4. data/app/controllers/concerns/spree/api/v3/admin/store_context.rb +1 -1
  5. data/app/controllers/concerns/spree/api/v3/admin/subclassed_resource.rb +1 -1
  6. data/app/controllers/concerns/spree/api/v3/cart_resolvable.rb +7 -0
  7. data/app/controllers/concerns/spree/api/v3/channel_resolution.rb +2 -2
  8. data/app/controllers/concerns/spree/api/v3/current_password_confirmation.rb +1 -1
  9. data/app/controllers/concerns/spree/api/v3/error_handler.rb +7 -2
  10. data/app/controllers/concerns/spree/api/v3/http_caching.rb +44 -11
  11. data/app/controllers/concerns/spree/api/v3/idempotent.rb +20 -5
  12. data/app/controllers/concerns/spree/api/v3/items_payload.rb +1 -1
  13. data/app/controllers/concerns/spree/api/v3/order_lock.rb +2 -2
  14. data/app/controllers/concerns/spree/api/v3/orders/delivery_actions.rb +1 -5
  15. data/app/controllers/concerns/spree/api/v3/orders/fulfillment_actions.rb +2 -10
  16. data/app/controllers/concerns/spree/api/v3/orders/post_sale_actions.rb +2 -10
  17. data/app/controllers/concerns/spree/api/v3/orders/shipping_label_actions.rb +4 -8
  18. data/app/controllers/concerns/spree/api/v3/permission_serialization.rb +9 -1
  19. data/app/controllers/concerns/spree/api/v3/seller/seller_context.rb +1 -1
  20. data/app/controllers/concerns/spree/api/v3/store/storefront_products.rb +5 -4
  21. data/app/controllers/concerns/spree/api/v3/storefront_gating.rb +11 -5
  22. data/app/controllers/spree/api/v3/admin/admin_users_controller.rb +0 -5
  23. data/app/controllers/spree/api/v3/admin/api_keys_controller.rb +1 -1
  24. data/app/controllers/spree/api/v3/admin/catalogs/order_minimums_controller.rb +0 -6
  25. data/app/controllers/spree/api/v3/admin/catalogs/quantity_rules_controller.rb +0 -4
  26. data/app/controllers/spree/api/v3/admin/catalogs_controller.rb +1 -1
  27. data/app/controllers/spree/api/v3/admin/channels_controller.rb +0 -4
  28. data/app/controllers/spree/api/v3/admin/collections/products_controller.rb +1 -2
  29. data/app/controllers/spree/api/v3/admin/commission_rates_controller.rb +2 -2
  30. data/app/controllers/spree/api/v3/admin/companies/addresses_controller.rb +0 -4
  31. data/app/controllers/spree/api/v3/admin/companies/invitations_controller.rb +1 -5
  32. data/app/controllers/spree/api/v3/admin/companies/memberships_controller.rb +0 -4
  33. data/app/controllers/spree/api/v3/admin/companies/tax_exemption_certificates_controller.rb +1 -9
  34. data/app/controllers/spree/api/v3/admin/companies/tax_identifiers_controller.rb +0 -4
  35. data/app/controllers/spree/api/v3/admin/companies_controller.rb +0 -4
  36. data/app/controllers/spree/api/v3/admin/countries_controller.rb +1 -1
  37. data/app/controllers/spree/api/v3/admin/coupon_codes_controller.rb +0 -4
  38. data/app/controllers/spree/api/v3/admin/custom_field_definitions_controller.rb +9 -1
  39. data/app/controllers/spree/api/v3/admin/custom_fields_controller.rb +0 -4
  40. data/app/controllers/spree/api/v3/admin/customer_groups_controller.rb +0 -4
  41. data/app/controllers/spree/api/v3/admin/customers/addresses_controller.rb +0 -4
  42. data/app/controllers/spree/api/v3/admin/customers/credit_cards_controller.rb +0 -4
  43. data/app/controllers/spree/api/v3/admin/customers/store_credits_controller.rb +0 -4
  44. data/app/controllers/spree/api/v3/admin/customers_controller.rb +2 -2
  45. data/app/controllers/spree/api/v3/admin/delivery_methods/rules_controller.rb +1 -1
  46. data/app/controllers/spree/api/v3/admin/delivery_methods_controller.rb +3 -5
  47. data/app/controllers/spree/api/v3/admin/delivery_profiles_controller.rb +1 -6
  48. data/app/controllers/spree/api/v3/admin/email_templates/drafts_controller.rb +40 -0
  49. data/app/controllers/spree/api/v3/admin/email_templates/previews_controller.rb +30 -0
  50. data/app/controllers/spree/api/v3/admin/email_templates/publications_controller.rb +30 -0
  51. data/app/controllers/spree/api/v3/admin/email_templates/restorations_controller.rb +34 -0
  52. data/app/controllers/spree/api/v3/admin/email_templates/revisions_controller.rb +35 -0
  53. data/app/controllers/spree/api/v3/admin/email_templates/sample_records_controller.rb +33 -0
  54. data/app/controllers/spree/api/v3/admin/email_templates/test_emails_controller.rb +40 -0
  55. data/app/controllers/spree/api/v3/admin/email_templates_controller.rb +46 -0
  56. data/app/controllers/spree/api/v3/admin/imports_controller.rb +1 -2
  57. data/app/controllers/spree/api/v3/admin/invitations_controller.rb +0 -7
  58. data/app/controllers/spree/api/v3/admin/me_controller.rb +1 -1
  59. data/app/controllers/spree/api/v3/admin/media_library_controller.rb +5 -5
  60. data/app/controllers/spree/api/v3/admin/order_routing_rules_controller.rb +0 -4
  61. data/app/controllers/spree/api/v3/admin/orders/deliveries_controller.rb +1 -5
  62. data/app/controllers/spree/api/v3/admin/orders/discount_codes_controller.rb +1 -1
  63. data/app/controllers/spree/api/v3/admin/orders/discounts_controller.rb +1 -1
  64. data/app/controllers/spree/api/v3/admin/orders/fulfillments_controller.rb +18 -16
  65. data/app/controllers/spree/api/v3/admin/orders/gift_cards_controller.rb +3 -3
  66. data/app/controllers/spree/api/v3/admin/orders/labels_controller.rb +2 -10
  67. data/app/controllers/spree/api/v3/admin/orders/payments_controller.rb +2 -14
  68. data/app/controllers/spree/api/v3/admin/orders/refunds_controller.rb +1 -5
  69. data/app/controllers/spree/api/v3/admin/orders_controller.rb +3 -3
  70. data/app/controllers/spree/api/v3/admin/password_resets_controller.rb +9 -7
  71. data/app/controllers/spree/api/v3/admin/price_lists_controller.rb +6 -53
  72. data/app/controllers/spree/api/v3/admin/prices_controller.rb +0 -4
  73. data/app/controllers/spree/api/v3/admin/products/digital_assets_controller.rb +2 -6
  74. data/app/controllers/spree/api/v3/admin/products/variants_controller.rb +0 -4
  75. data/app/controllers/spree/api/v3/admin/products_controller.rb +1 -1
  76. data/app/controllers/spree/api/v3/admin/promotion_actions_controller.rb +0 -4
  77. data/app/controllers/spree/api/v3/admin/promotion_rules_controller.rb +0 -4
  78. data/app/controllers/spree/api/v3/admin/purchase_orders_controller.rb +1 -1
  79. data/app/controllers/spree/api/v3/admin/resource_controller.rb +1 -1
  80. data/app/controllers/spree/api/v3/admin/seller_payouts_controller.rb +1 -9
  81. data/app/controllers/spree/api/v3/admin/seller_requirement_submissions_controller.rb +2 -10
  82. data/app/controllers/spree/api/v3/admin/seller_transfers_controller.rb +0 -4
  83. data/app/controllers/spree/api/v3/admin/sellers/invitations_controller.rb +1 -1
  84. data/app/controllers/spree/api/v3/admin/sellers/payouts_controller.rb +1 -1
  85. data/app/controllers/spree/api/v3/admin/sellers_controller.rb +2 -10
  86. data/app/controllers/spree/api/v3/admin/setup_controller.rb +3 -11
  87. data/app/controllers/spree/api/v3/admin/stock_transfers_controller.rb +1 -1
  88. data/app/controllers/spree/api/v3/admin/store_controller.rb +6 -1
  89. data/app/controllers/spree/api/v3/admin/tags_controller.rb +8 -5
  90. data/app/controllers/spree/api/v3/admin/webhook_endpoints_controller.rb +17 -12
  91. data/app/controllers/spree/api/v3/admin/webhook_events_controller.rb +25 -0
  92. data/app/controllers/spree/api/v3/base_controller.rb +10 -0
  93. data/app/controllers/spree/api/v3/resource_controller.rb +44 -1
  94. data/app/controllers/spree/api/v3/seller/auth_controller.rb +2 -2
  95. data/app/controllers/spree/api/v3/seller/countries_controller.rb +1 -1
  96. data/app/controllers/spree/api/v3/seller/exports_controller.rb +3 -3
  97. data/app/controllers/spree/api/v3/seller/invitation_acceptances_controller.rb +3 -3
  98. data/app/controllers/spree/api/v3/seller/invitations_controller.rb +1 -1
  99. data/app/controllers/spree/api/v3/seller/me_controller.rb +1 -1
  100. data/app/controllers/spree/api/v3/seller/orders/labels_controller.rb +1 -1
  101. data/app/controllers/spree/api/v3/seller/password_resets_controller.rb +10 -11
  102. data/app/controllers/spree/api/v3/seller/products_controller.rb +2 -1
  103. data/app/controllers/spree/api/v3/seller/requirement_submissions_controller.rb +1 -1
  104. data/app/controllers/spree/api/v3/seller/team_controller.rb +1 -1
  105. data/app/controllers/spree/api/v3/store/carts/discount_codes_controller.rb +1 -1
  106. data/app/controllers/spree/api/v3/store/carts/fulfillments_controller.rb +3 -11
  107. data/app/controllers/spree/api/v3/store/carts/gift_cards_controller.rb +5 -3
  108. data/app/controllers/spree/api/v3/store/carts/items_controller.rb +6 -2
  109. data/app/controllers/spree/api/v3/store/carts/payment_sessions_controller.rb +1 -1
  110. data/app/controllers/spree/api/v3/store/carts/payments_controller.rb +5 -3
  111. data/app/controllers/spree/api/v3/store/carts/po_documents_controller.rb +2 -2
  112. data/app/controllers/spree/api/v3/store/carts/store_credits_controller.rb +2 -0
  113. data/app/controllers/spree/api/v3/store/carts_controller.rb +9 -6
  114. data/app/controllers/spree/api/v3/store/companies/addresses_controller.rb +0 -4
  115. data/app/controllers/spree/api/v3/store/companies/invitations_controller.rb +1 -5
  116. data/app/controllers/spree/api/v3/store/company_invitations_controller.rb +1 -1
  117. data/app/controllers/spree/api/v3/store/customer/addresses_controller.rb +0 -4
  118. data/app/controllers/spree/api/v3/store/customer/credit_cards_controller.rb +0 -4
  119. data/app/controllers/spree/api/v3/store/customer/data_requests_controller.rb +0 -5
  120. data/app/controllers/spree/api/v3/store/customer/digital_links_controller.rb +0 -4
  121. data/app/controllers/spree/api/v3/store/customer/gift_cards_controller.rb +0 -4
  122. data/app/controllers/spree/api/v3/store/customer/orders_controller.rb +0 -4
  123. data/app/controllers/spree/api/v3/store/customer/password_resets_controller.rb +8 -6
  124. data/app/controllers/spree/api/v3/store/customer/payment_setup_sessions_controller.rb +0 -4
  125. data/app/controllers/spree/api/v3/store/customer/store_credits_controller.rb +0 -5
  126. data/app/controllers/spree/api/v3/store/data_request_downloads_controller.rb +1 -1
  127. data/app/controllers/spree/api/v3/store/delivery_methods_controller.rb +1 -1
  128. data/app/controllers/spree/api/v3/store/newsletter_subscribers_controller.rb +5 -14
  129. data/app/controllers/spree/api/v3/store/orders/claims_controller.rb +1 -5
  130. data/app/controllers/spree/api/v3/store/orders/returns_controller.rb +1 -5
  131. data/app/controllers/spree/api/v3/store/wishlist_items_controller.rb +0 -4
  132. data/app/serializers/spree/api/v3/admin/address_serializer.rb +5 -7
  133. data/app/serializers/spree/api/v3/admin/api_key_serializer.rb +2 -6
  134. data/app/serializers/spree/api/v3/admin/catalog_assignment_serializer.rb +1 -3
  135. data/app/serializers/spree/api/v3/admin/catalog_order_minimum_serializer.rb +1 -7
  136. data/app/serializers/spree/api/v3/admin/catalog_product_term_serializer.rb +1 -3
  137. data/app/serializers/spree/api/v3/admin/catalog_quantity_rule_serializer.rb +1 -3
  138. data/app/serializers/spree/api/v3/admin/channel_serializer.rb +5 -6
  139. data/app/serializers/spree/api/v3/admin/claim_reason_serializer.rb +1 -3
  140. data/app/serializers/spree/api/v3/admin/commission_rule_serializer.rb +1 -3
  141. data/app/serializers/spree/api/v3/admin/coupon_code_serializer.rb +1 -7
  142. data/app/serializers/spree/api/v3/admin/credit_card_serializer.rb +1 -7
  143. data/app/serializers/spree/api/v3/admin/custom_field_definition_serializer.rb +6 -2
  144. data/app/serializers/spree/api/v3/admin/customer_serializer.rb +2 -10
  145. data/app/serializers/spree/api/v3/admin/data_request_serializer.rb +2 -6
  146. data/app/serializers/spree/api/v3/admin/delivery_method_serializer.rb +8 -22
  147. data/app/serializers/spree/api/v3/admin/delivery_origin_group_serializer.rb +1 -3
  148. data/app/serializers/spree/api/v3/admin/delivery_serializer.rb +1 -3
  149. data/app/serializers/spree/api/v3/admin/delivery_zone_serializer.rb +1 -7
  150. data/app/serializers/spree/api/v3/admin/digital_asset_serializer.rb +4 -2
  151. data/app/serializers/spree/api/v3/admin/email_template_draft_serializer.rb +19 -0
  152. data/app/serializers/spree/api/v3/admin/email_template_preview_serializer.rb +38 -0
  153. data/app/serializers/spree/api/v3/admin/email_template_revision_serializer.rb +18 -0
  154. data/app/serializers/spree/api/v3/admin/email_template_sample_record_serializer.rb +13 -0
  155. data/app/serializers/spree/api/v3/admin/email_template_serializer.rb +61 -0
  156. data/app/serializers/spree/api/v3/admin/exchange_serializer.rb +1 -3
  157. data/app/serializers/spree/api/v3/admin/export_serializer.rb +1 -7
  158. data/app/serializers/spree/api/v3/admin/fulfillment_item_serializer.rb +1 -7
  159. data/app/serializers/spree/api/v3/admin/fulfillment_serializer.rb +1 -7
  160. data/app/serializers/spree/api/v3/admin/gift_card_serializer.rb +1 -7
  161. data/app/serializers/spree/api/v3/admin/line_item_serializer.rb +2 -6
  162. data/app/serializers/spree/api/v3/admin/market_serializer.rb +4 -2
  163. data/app/serializers/spree/api/v3/admin/media_serializer.rb +1 -3
  164. data/app/serializers/spree/api/v3/admin/order_cancellation_reason_serializer.rb +1 -3
  165. data/app/serializers/spree/api/v3/admin/order_group_serializer.rb +3 -9
  166. data/app/serializers/spree/api/v3/admin/order_routing_rule_serializer.rb +1 -3
  167. data/app/serializers/spree/api/v3/admin/order_serializer.rb +5 -15
  168. data/app/serializers/spree/api/v3/admin/package_type_serializer.rb +1 -3
  169. data/app/serializers/spree/api/v3/admin/payment_method_serializer.rb +7 -1
  170. data/app/serializers/spree/api/v3/admin/payment_serializer.rb +2 -7
  171. data/app/serializers/spree/api/v3/admin/permission_serializer.rb +4 -4
  172. data/app/serializers/spree/api/v3/admin/price_rule_serializer.rb +1 -3
  173. data/app/serializers/spree/api/v3/admin/product_serializer.rb +2 -10
  174. data/app/serializers/spree/api/v3/admin/product_submission_serializer.rb +2 -10
  175. data/app/serializers/spree/api/v3/admin/product_type_serializer.rb +1 -3
  176. data/app/serializers/spree/api/v3/admin/promotion_action_serializer.rb +1 -3
  177. data/app/serializers/spree/api/v3/admin/promotion_rule_serializer.rb +1 -3
  178. data/app/serializers/spree/api/v3/admin/purchase_order_item_serializer.rb +2 -15
  179. data/app/serializers/spree/api/v3/admin/purchase_order_serializer.rb +2 -15
  180. data/app/serializers/spree/api/v3/admin/refund_reason_serializer.rb +1 -3
  181. data/app/serializers/spree/api/v3/admin/refund_serializer.rb +4 -1
  182. data/app/serializers/spree/api/v3/admin/return_line_item_serializer.rb +1 -0
  183. data/app/serializers/spree/api/v3/admin/return_reason_serializer.rb +1 -3
  184. data/app/serializers/spree/api/v3/admin/return_serializer.rb +3 -11
  185. data/app/serializers/spree/api/v3/admin/saved_report_serializer.rb +1 -3
  186. data/app/serializers/spree/api/v3/admin/seller_payout_serializer.rb +4 -2
  187. data/app/serializers/spree/api/v3/admin/seller_requirement_status_serializer.rb +2 -6
  188. data/app/serializers/spree/api/v3/admin/seller_requirement_submission_serializer.rb +1 -7
  189. data/app/serializers/spree/api/v3/admin/seller_serializer.rb +5 -15
  190. data/app/serializers/spree/api/v3/admin/seller_transfer_serializer.rb +4 -2
  191. data/app/serializers/spree/api/v3/admin/shipping_label_serializer.rb +6 -19
  192. data/app/serializers/spree/api/v3/admin/stock_level_serializer.rb +1 -3
  193. data/app/serializers/spree/api/v3/admin/stock_location_serializer.rb +1 -3
  194. data/app/serializers/spree/api/v3/admin/stock_movement_serializer.rb +1 -3
  195. data/app/serializers/spree/api/v3/admin/stock_receipt_item_serializer.rb +1 -7
  196. data/app/serializers/spree/api/v3/admin/stock_receipt_serializer.rb +1 -3
  197. data/app/serializers/spree/api/v3/admin/stock_reservation_serializer.rb +1 -3
  198. data/app/serializers/spree/api/v3/admin/stock_transfer_item_serializer.rb +1 -3
  199. data/app/serializers/spree/api/v3/admin/store_credit_event_serializer.rb +1 -3
  200. data/app/serializers/spree/api/v3/admin/store_credit_serializer.rb +4 -18
  201. data/app/serializers/spree/api/v3/admin/store_serializer.rb +24 -6
  202. data/app/serializers/spree/api/v3/admin/supplier_serializer.rb +1 -3
  203. data/app/serializers/spree/api/v3/admin/tax_exemption_certificate_serializer.rb +3 -9
  204. data/app/serializers/spree/api/v3/admin/tax_identifier_serializer.rb +1 -3
  205. data/app/serializers/spree/api/v3/admin/tax_line_serializer.rb +5 -1
  206. data/app/serializers/spree/api/v3/admin/tax_rate_serializer.rb +1 -7
  207. data/app/serializers/spree/api/v3/admin/variant_serializer.rb +6 -7
  208. data/app/serializers/spree/api/v3/admin/webhook_delivery_serializer.rb +1 -3
  209. data/app/serializers/spree/api/v3/admin/webhook_event_serializer.rb +23 -0
  210. data/app/serializers/spree/api/v3/applied_promotion_serializer.rb +2 -4
  211. data/app/serializers/spree/api/v3/base_serializer.rb +20 -0
  212. data/app/serializers/spree/api/v3/cart_serializer.rb +17 -45
  213. data/app/serializers/spree/api/v3/category_serializer.rb +5 -15
  214. data/app/serializers/spree/api/v3/claim_line_item_serializer.rb +11 -26
  215. data/app/serializers/spree/api/v3/claim_serializer.rb +2 -15
  216. data/app/serializers/spree/api/v3/collection_serializer.rb +1 -3
  217. data/app/serializers/spree/api/v3/company_serializer.rb +1 -3
  218. data/app/serializers/spree/api/v3/custom_field_serializer.rb +1 -2
  219. data/app/serializers/spree/api/v3/delivery_rate_serializer.rb +3 -23
  220. data/app/serializers/spree/api/v3/digital_asset_serializer.rb +1 -3
  221. data/app/serializers/spree/api/v3/digital_link_serializer.rb +3 -9
  222. data/app/serializers/spree/api/v3/discount_serializer.rb +1 -12
  223. data/app/serializers/spree/api/v3/exchange_line_item_serializer.rb +9 -27
  224. data/app/serializers/spree/api/v3/exchange_serializer.rb +2 -15
  225. data/app/serializers/spree/api/v3/export_serializer.rb +1 -3
  226. data/app/serializers/spree/api/v3/fee_serializer.rb +2 -10
  227. data/app/serializers/spree/api/v3/fulfillment_serializer.rb +4 -11
  228. data/app/serializers/spree/api/v3/gift_card_batch_serializer.rb +1 -3
  229. data/app/serializers/spree/api/v3/gift_card_serializer.rb +5 -17
  230. data/app/serializers/spree/api/v3/import_row_serializer.rb +2 -6
  231. data/app/serializers/spree/api/v3/import_serializer.rb +3 -14
  232. data/app/serializers/spree/api/v3/invitation_serializer.rb +2 -19
  233. data/app/serializers/spree/api/v3/line_item_serializer.rb +6 -20
  234. data/app/serializers/spree/api/v3/media_event_serializer.rb +1 -3
  235. data/app/serializers/spree/api/v3/media_serializer.rb +1 -3
  236. data/app/serializers/spree/api/v3/newsletter_subscriber_request_event_serializer.rb +35 -0
  237. data/app/serializers/spree/api/v3/newsletter_subscriber_serializer.rb +2 -6
  238. data/app/serializers/spree/api/v3/option_value_serializer.rb +1 -3
  239. data/app/serializers/spree/api/v3/order_group_serializer.rb +2 -23
  240. data/app/serializers/spree/api/v3/order_serializer.rb +12 -38
  241. data/app/serializers/spree/api/v3/password_reset_requested_event_serializer.rb +29 -0
  242. data/app/serializers/spree/api/v3/payment_method_serializer.rb +2 -6
  243. data/app/serializers/spree/api/v3/payment_serializer.rb +5 -10
  244. data/app/serializers/spree/api/v3/payment_session_serializer.rb +3 -9
  245. data/app/serializers/spree/api/v3/payment_setup_session_serializer.rb +3 -11
  246. data/app/serializers/spree/api/v3/policy_serializer.rb +1 -3
  247. data/app/serializers/spree/api/v3/price_history_serializer.rb +1 -3
  248. data/app/serializers/spree/api/v3/price_serializer.rb +1 -3
  249. data/app/serializers/spree/api/v3/product_publication_serializer.rb +1 -7
  250. data/app/serializers/spree/api/v3/product_serializer.rb +7 -21
  251. data/app/serializers/spree/api/v3/product_submission_serializer.rb +26 -0
  252. data/app/serializers/spree/api/v3/purchase_order_event_serializer.rb +23 -4
  253. data/app/serializers/spree/api/v3/refund_serializer.rb +3 -11
  254. data/app/serializers/spree/api/v3/return_line_item_serializer.rb +12 -19
  255. data/app/serializers/spree/api/v3/return_serializer.rb +6 -15
  256. data/app/serializers/spree/api/v3/saved_report_event_serializer.rb +23 -0
  257. data/app/serializers/spree/api/v3/seller/delivery_method_serializer.rb +1 -7
  258. data/app/serializers/spree/api/v3/seller/delivery_rate_serializer.rb +1 -7
  259. data/app/serializers/spree/api/v3/seller/delivery_serializer.rb +1 -3
  260. data/app/serializers/spree/api/v3/seller/delivery_zone_serializer.rb +1 -3
  261. data/app/serializers/spree/api/v3/seller/exchange_serializer.rb +1 -3
  262. data/app/serializers/spree/api/v3/seller/fulfillment_item_serializer.rb +1 -7
  263. data/app/serializers/spree/api/v3/seller/fulfillment_serializer.rb +2 -6
  264. data/app/serializers/spree/api/v3/seller/invitation_serializer.rb +1 -3
  265. data/app/serializers/spree/api/v3/seller/order_line_item_serializer.rb +7 -13
  266. data/app/serializers/spree/api/v3/seller/order_serializer.rb +4 -25
  267. data/app/serializers/spree/api/v3/seller/payout_serializer.rb +4 -2
  268. data/app/serializers/spree/api/v3/seller/product_serializer.rb +1 -7
  269. data/app/serializers/spree/api/v3/seller/product_submission_serializer.rb +1 -21
  270. data/app/serializers/spree/api/v3/seller/profile_serializer.rb +2 -6
  271. data/app/serializers/spree/api/v3/seller/requirement_status_serializer.rb +3 -9
  272. data/app/serializers/spree/api/v3/seller/return_serializer.rb +3 -15
  273. data/app/serializers/spree/api/v3/seller/transfer_serializer.rb +4 -2
  274. data/app/serializers/spree/api/v3/seller_serializer.rb +1 -3
  275. data/app/serializers/spree/api/v3/shipping_label_event_serializer.rb +22 -4
  276. data/app/serializers/spree/api/v3/stock_level_serializer.rb +1 -7
  277. data/app/serializers/spree/api/v3/stock_movement_serializer.rb +1 -3
  278. data/app/serializers/spree/api/v3/stock_receipt_event_serializer.rb +20 -4
  279. data/app/serializers/spree/api/v3/stock_transfer_serializer.rb +1 -7
  280. data/app/serializers/spree/api/v3/store_credit_event_serializer.rb +2 -11
  281. data/app/serializers/spree/api/v3/store_credit_serializer.rb +2 -24
  282. data/app/serializers/spree/api/v3/supplier_event_serializer.rb +6 -4
  283. data/app/serializers/spree/api/v3/tax_line_serializer.rb +10 -20
  284. data/app/serializers/spree/api/v3/variant_serializer.rb +7 -21
  285. data/app/serializers/spree/api/v3/wishlist_item_serializer.rb +1 -11
  286. data/app/serializers/spree/api/v3/wishlist_serializer.rb +2 -6
  287. data/app/subscribers/spree/webhook_event_subscriber.rb +3 -10
  288. data/config/initializers/pagy.rb +1 -1
  289. data/config/initializers/typelizer.rb +6 -8
  290. data/config/locales/ar.yml +15 -0
  291. data/config/locales/be.yml +15 -0
  292. data/config/locales/bg.yml +15 -0
  293. data/config/locales/ca.yml +15 -0
  294. data/config/locales/cs.yml +15 -0
  295. data/config/locales/da.yml +15 -0
  296. data/config/locales/de-CH.yml +11 -0
  297. data/config/locales/de.yml +15 -0
  298. data/config/locales/el.yml +15 -0
  299. data/config/locales/en.yml +5 -40
  300. data/config/locales/es-CL.yml +10 -0
  301. data/config/locales/es-EC.yml +11 -0
  302. data/config/locales/es-MX.yml +12 -0
  303. data/config/locales/es.yml +15 -0
  304. data/config/locales/et.yml +15 -0
  305. data/config/locales/fa.yml +15 -0
  306. data/config/locales/fi.yml +15 -0
  307. data/config/locales/fr.yml +15 -0
  308. data/config/locales/hu.yml +15 -0
  309. data/config/locales/id.yml +15 -0
  310. data/config/locales/it.yml +15 -0
  311. data/config/locales/ja.yml +15 -0
  312. data/config/locales/km.yml +15 -0
  313. data/config/locales/ko.yml +15 -0
  314. data/config/locales/ku.yml +15 -0
  315. data/config/locales/lt.yml +15 -0
  316. data/config/locales/lv.yml +15 -0
  317. data/config/locales/nb.yml +15 -0
  318. data/config/locales/ne.yml +15 -0
  319. data/config/locales/nl.yml +15 -0
  320. data/config/locales/pl.yml +15 -0
  321. data/config/locales/pt-BR.yml +13 -0
  322. data/config/locales/pt.yml +15 -0
  323. data/config/locales/ro.yml +15 -0
  324. data/config/locales/ru.yml +15 -0
  325. data/config/locales/sk.yml +15 -0
  326. data/config/locales/sl-SI.yml +15 -0
  327. data/config/locales/sv.yml +15 -0
  328. data/config/locales/th.yml +15 -0
  329. data/config/locales/tr.yml +15 -0
  330. data/config/locales/uk.yml +15 -0
  331. data/config/locales/vi.yml +15 -0
  332. data/config/locales/zh-CN.yml +15 -0
  333. data/config/locales/zh-TW.yml +15 -0
  334. data/config/routes.rb +49 -99
  335. data/lib/spree/api/dependencies.rb +53 -274
  336. data/lib/spree/api/openapi/schema_helper.rb +1 -1
  337. data/lib/spree/api/typelizer_generation.rb +35 -0
  338. data/lib/spree/api/webhook_event_types.rb +140 -0
  339. data/lib/spree/api.rb +0 -2
  340. metadata +71 -36
  341. data/config/i18n-tasks.yml +0 -40
  342. data/config/initializers/alba.rb +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cbd216e65a6f6ce291a04b750595491f827262d4de353562ac43fa51d69c376e
4
- data.tar.gz: ed6181390f17841dc63104e068e6812d936dc29d3896c8366ea27cebc6817274
3
+ metadata.gz: 3816f80ebaf4e6b8bc42854938340dce8bc17f6190d55337a7e08950fedf7fb1
4
+ data.tar.gz: 42034e2f05201a30da2d13345b761e1376523ecf98f64668de3538de772a19f2
5
5
  SHA512:
6
- metadata.gz: 50b7fd005e9f4c80d83c1be99a3e4abf9c84a947e5b801fae461a4596b3e5005a376c2fbb1a6e9aeea063492cdc3548116cfdca5621b551598fbcbac1635fb4c
7
- data.tar.gz: '00699269b7d5c5c53d2154a32784c48a8e42a9a2759c05e387fb2218a5725249ab52179861f69b0afa217c5fe429a855fcc3077b9d21dce2efcfea6317cad20e'
6
+ metadata.gz: f315aff41e1e8731961bfa6cf18bba36428e222aa11ed341b66c9b74bee863eb53b5cece23b361a73a036f5d744e25037e25ec1a49004653a8a7f0448f29a10c
7
+ data.tar.gz: 34d2faa68118ec0bba15cf75b5711ade7aa0b1d817606180a3e7fb2a57bfdb816799f2911b83b41833f07251f0781d9d5e9046251eb6068356956839b38fc59e
data/Rakefile CHANGED
@@ -67,39 +67,12 @@ namespace :rswag do
67
67
  end
68
68
 
69
69
  namespace :typelizer do
70
- desc 'Generate TypeScript types for both Store and Admin SDKs'
70
+ desc 'Generate TypeScript types for every SDK (runs in spree_emails, where all serializers load)'
71
71
  task :generate do
72
- ENV['RAILS_ENV'] ||= 'test'
73
- ENV['DISABLE_TYPELIZER'] = 'false'
74
-
75
- require File.expand_path('spec/dummy/config/environment', __dir__)
76
-
77
- # Eager load serializers so typelizer can find them
78
- serializers_path = File.expand_path('app/serializers/spree/api/v3', __dir__)
79
- Rails.autoloaders.main.eager_load_dir(serializers_path)
80
-
81
- require 'typelizer/generator'
82
-
83
- # Writer config is in config/initializers/typelizer.rb
84
- Typelizer::Generator.call(force: true)
85
-
86
- # Post-process: convert `type Foo = {` to `interface Foo {` for declaration merging support.
87
- # This lets SDK consumers extend generated types via `declare module '@spree/sdk' { interface Product { ... } }`.
88
- api_root = Spree::Api::Engine.root
89
- [
90
- api_root.join('../../packages/sdk/src/types/generated'),
91
- api_root.join('../../packages/admin-sdk/src/types/generated')
92
- ].each do |dir|
93
- Dir[File.join(dir, '*.ts')].each do |file|
94
- next if File.basename(file) == 'index.ts'
95
-
96
- content = File.read(file)
97
- updated = content.gsub(/^type (\w+) = \{/, 'interface \1 {')
98
- File.write(file, updated) if updated != content
99
- end
72
+ emails_dir = File.expand_path('../emails', __dir__)
73
+ Bundler.with_unbundled_env do
74
+ sh "cd #{emails_dir} && bundle exec rake typelizer:generate"
100
75
  end
101
-
102
- puts "Generated types → packages/sdk/src/types/generated/ & packages/admin-sdk/src/types/generated/"
103
76
  end
104
77
 
105
78
  desc 'Clean and regenerate TypeScript types'
@@ -0,0 +1,139 @@
1
+ module Spree
2
+ module Api
3
+ module V3
4
+ module Admin
5
+ # Finds the editable email template a request is about, from its
6
+ # dotted key, for the language the request names.
7
+ module EmailTemplateLookup
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ scoped_resource :email_templates
12
+
13
+ before_action :load_email_template
14
+
15
+ rescue_from Spree::EmailTemplates::NoSampleRecord, with: :render_no_sample
16
+ rescue_from Liquid::Error, MRML::Error, with: :render_render_error
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :email_template
22
+
23
+ def load_email_template
24
+ @email_template = Spree::EmailTemplates::Entry.for_id(
25
+ current_store, params[:email_template_id] || params[:id], locale: language
26
+ )
27
+ end
28
+
29
+ # A language code, or "any" for the version every language uses. Named
30
+ # `language` rather than `locale`, which picks the response's language.
31
+ def language
32
+ @language ||= params[:language].to_s.strip.presence || Spree::EmailTemplate::ANY_LOCALE
33
+ end
34
+
35
+ def serialize_email_template(reload: false)
36
+ load_email_template if reload
37
+ Spree.api.admin_email_template_serializer.new(email_template, params: serializer_params).to_h
38
+ end
39
+
40
+ def serializer_class
41
+ Spree.api.admin_email_template_serializer
42
+ end
43
+
44
+ # Renders the template as it stands after a workflow ran, or why the
45
+ # workflow refused.
46
+ def render_email_template_result(result, status: :ok)
47
+ return render_stale_draft if result.error&.value == :stale
48
+ return render_template_problems(result.value) if result.error&.value == :invalid_template
49
+ return render_result_error(result) unless result.success?
50
+
51
+ render json: serialize_email_template(reload: true), status: status
52
+ end
53
+
54
+ # Every published version of the template in the requested language.
55
+ def email_template_revisions
56
+ Spree::EmailTemplateRevision.where(
57
+ email_template: current_store.email_templates.for_key(email_template.key, language)
58
+ )
59
+ end
60
+
61
+ # An unsaved subject and body are previewed only when sent, so an
62
+ # empty body still previews as empty. `branding` previews unsaved
63
+ # colors and font.
64
+ def preview_arguments
65
+ arguments = params.permit(:record_id, :subject, :body).to_h.symbolize_keys
66
+ arguments[:locale] = language
67
+ arguments[:email_key] = params[:email_key].to_s.tr('.', '/').presence
68
+ arguments[:branding] = params.fetch(:branding, {}).permit(*Spree::Emails::Branding.attribute_names).to_h
69
+ arguments
70
+ end
71
+
72
+ # Samples show a real record of the store (the latest order, a
73
+ # company), so previewing one needs permission to read it.
74
+ def authorize_sample_data!
75
+ missing = sample_classes.flat_map { |sample| Array(sample.try(:required_permissions)) }.uniq.
76
+ reject { |key| holds_permission?(key) }
77
+ return if missing.empty?
78
+
79
+ render_error(
80
+ code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:access_denied],
81
+ message: I18n.t('spree.email_templates.sample_needs_permission', permissions: missing.to_sentence),
82
+ status: :forbidden,
83
+ details: { required_scope: missing.first }
84
+ )
85
+ end
86
+
87
+ # A preview shows one email; publishing the layout or a partial
88
+ # renders every email, so it needs what all of their samples need.
89
+ def sample_classes
90
+ if action_name == 'create' && controller_name == 'publications' && !email_template.definition.email?
91
+ Spree.editable_email_templates.emails.map(&:sample_class)
92
+ else
93
+ [build_preview.email.sample_class]
94
+ end
95
+ end
96
+
97
+ def build_preview
98
+ Spree::EmailTemplates::Preview.new(store: current_store, key: email_template.key, strict: true, **preview_arguments)
99
+ end
100
+
101
+ def render_template_problems(problems)
102
+ problems = problems.map { |problem| problem.merge(email: problem[:email].tr('/', '.')) }
103
+
104
+ render_error(
105
+ code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:email_template_invalid],
106
+ message: problems.map { |problem| problem[:message] }.uniq.to_sentence,
107
+ status: :unprocessable_content,
108
+ details: { problems: problems }
109
+ )
110
+ end
111
+
112
+ # Attributed to the template being edited, whose lines the editor marks.
113
+ def render_render_error(error)
114
+ render_template_problems([{ email: email_template.id, message: error.message, line: error.try(:line_number) }])
115
+ end
116
+
117
+ def render_no_sample(error)
118
+ render_error(
119
+ code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:email_template_no_sample],
120
+ message: error.message,
121
+ status: :unprocessable_content
122
+ )
123
+ end
124
+
125
+ def render_stale_draft
126
+ saved_by = email_template.draft&.updated_by&.actor_label
127
+
128
+ render_error(
129
+ code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:email_template_stale],
130
+ message: I18n.t('spree.email_templates.stale_draft', name: saved_by || I18n.t('spree.email_templates.another_admin')),
131
+ status: :conflict,
132
+ details: { updated_by: saved_by }
133
+ )
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -44,7 +44,7 @@ module Spree
44
44
  if secret_api_key && store_id_header && secret_api_key.store&.prefixed_id != store_id_header
45
45
  render_error(
46
46
  code: ErrorHandler::ERROR_CODES[:access_denied],
47
- message: Spree.t('api.errors.store_mismatch', default: 'The requested store does not match the store this API key belongs to.'),
47
+ message: I18n.t('spree.api.errors.store_mismatch'),
48
48
  status: :forbidden
49
49
  )
50
50
  return
@@ -103,7 +103,7 @@ module Spree
103
103
  def render_unknown_type
104
104
  render_error(
105
105
  code: self.class.unknown_type_error_code,
106
- message: Spree.t("api.#{self.class.unknown_type_error_code}",
106
+ message: I18n.t("spree.api.#{self.class.unknown_type_error_code}",
107
107
  default: 'Unknown type'),
108
108
  status: :unprocessable_content
109
109
  )
@@ -57,6 +57,13 @@ module Spree
57
57
  @cart = @cart.remove_out_of_stock_items!
58
58
  end
59
59
 
60
+ # Drops a batch coupon code the cart no longer holds. Unlike the line
61
+ # sweep this runs after writes too, since an API client may rely on
62
+ # write responses alone to learn why its discount went.
63
+ def sweep_unavailable_coupon_code!
64
+ @cart = @cart.remove_unavailable_coupon_code!
65
+ end
66
+
60
67
  # Render what the checkout produced (for the complete action).
61
68
  #
62
69
  # A checkout spanning several sellers produced a group of orders rather
@@ -59,7 +59,7 @@ module Spree
59
59
  if header && header.id != bound.id
60
60
  render_error(
61
61
  code: ErrorHandler::ERROR_CODES[:channel_mismatch],
62
- message: Spree.t('api.errors.channel_mismatch', default: 'The requested channel does not match the channel this API key is bound to'),
62
+ message: I18n.t('spree.api.errors.channel_mismatch'),
63
63
  status: :unprocessable_entity
64
64
  )
65
65
  return
@@ -68,7 +68,7 @@ module Spree
68
68
  unless bound.active?
69
69
  render_error(
70
70
  code: ErrorHandler::ERROR_CODES[:channel_inactive],
71
- message: Spree.t('api.errors.channel_inactive', default: 'The channel this API key is bound to is not active'),
71
+ message: I18n.t('spree.api.errors.channel_inactive'),
72
72
  status: :forbidden
73
73
  )
74
74
  return
@@ -39,7 +39,7 @@ module Spree
39
39
  def render_current_password_invalid
40
40
  render_error(
41
41
  code: ErrorHandler::ERROR_CODES[:current_password_invalid],
42
- message: Spree.t(:current_password_invalid, scope: :api),
42
+ message: I18n.t('spree.api.current_password_invalid'),
43
43
  status: :unprocessable_content
44
44
  )
45
45
  end
@@ -74,6 +74,11 @@ module Spree
74
74
  # Export errors
75
75
  export_not_ready: 'export_not_ready',
76
76
 
77
+ # Email template errors
78
+ email_template_stale: 'email_template_stale',
79
+ email_template_invalid: 'email_template_invalid',
80
+ email_template_no_sample: 'email_template_no_sample',
81
+
77
82
  # Rate limiting errors
78
83
  rate_limit_exceeded: 'rate_limit_exceeded',
79
84
 
@@ -155,7 +160,7 @@ module Spree
155
160
  # Workflows reject with a symbol naming the reason. Translate it,
156
161
  # falling back to the symbol so a missing key is visible rather
157
162
  # than silently blank.
158
- render_error(code: code, message: Spree.t(error, default: error.to_s.humanize), status: status)
163
+ render_error(code: code, message: I18n.t("spree.#{error}", default: error.to_s.humanize), status: status)
159
164
  else
160
165
  render_error(code: code, message: error.to_s, status: status)
161
166
  end
@@ -311,7 +316,7 @@ module Spree
311
316
  model_name&.humanize || 'record'
312
317
  end
313
318
 
314
- Spree.t(:record_not_found, scope: 'api', model: label)
319
+ I18n.t('spree.api.record_not_found', model: label)
315
320
  end
316
321
 
317
322
  # Extract clean model name from exception
@@ -11,6 +11,33 @@ module Spree
11
11
  module HttpCaching
12
12
  extend ActiveSupport::Concern
13
13
 
14
+ # Every request header that changes a publicly cacheable response.
15
+ # A shared cache (CDN, reverse proxy) keys stored responses on these,
16
+ # so a header missing here lets one visitor's response be served to
17
+ # another:
18
+ # - +Accept+ — response format
19
+ # - +X-Spree-Api-Key+ — the publishable key selects the store (and
20
+ # may bind a channel)
21
+ # - +Authorization+ — a customer JWT turns the response private
22
+ # (customer-group prices, gated catalog); without it a guest
23
+ # response could be served to a signed-in customer
24
+ # - +X-Spree-Country+ — selects the market (currency, prices, tax
25
+ # display, availability)
26
+ # - +X-Spree-Currency+ / +X-Spree-Locale+ — currency and language
27
+ # - +X-Spree-Channel+ — price hiding + channel-scoped visibility
28
+ #
29
+ # Query-param equivalents (+?country=+, +?currency=+, +?locale=+)
30
+ # are part of the URL and so already part of every cache key.
31
+ VARY_HEADERS = %w[
32
+ Accept
33
+ X-Spree-Api-Key
34
+ Authorization
35
+ X-Spree-Country
36
+ X-Spree-Currency
37
+ X-Spree-Locale
38
+ X-Spree-Channel
39
+ ].freeze
40
+
14
41
  included do
15
42
  after_action :set_vary_headers
16
43
  end
@@ -22,13 +49,11 @@ module Spree
22
49
  current_user.nil?
23
50
  end
24
51
 
25
- # Set Vary headers to ensure proper CDN caching by currency/locale/channel.
26
- # X-Spree-Channel is included because the resolved channel changes the
27
- # serialized body (price hiding + channel-scoped visibility), so a shared
28
- # cache must not serve one channel's guest response to another channel.
52
+ # Set Vary so a shared cache stores one guest response per
53
+ # store/market/currency/locale/channel combination (see VARY_HEADERS).
29
54
  def set_vary_headers
30
55
  if guest_user?
31
- response.headers['Vary'] = 'Accept, x-spree-currency, x-spree-locale, x-spree-channel'
56
+ response.headers['Vary'] = VARY_HEADERS.join(', ')
32
57
  else
33
58
  response.headers['Cache-Control'] = 'private, no-store'
34
59
  end
@@ -70,12 +95,12 @@ module Spree
70
95
 
71
96
  expires_in expires_in, public: true
72
97
 
73
- # Use Rails' stale? which handles ETag and Last-Modified. The channel
74
- # is folded into the ETag so a shared cache never serves one channel's
75
- # guest response to another; Last-Modified mirrors the resource's own
76
- # timestamp as before.
98
+ # Use Rails' stale? which handles ETag and Last-Modified. The request
99
+ # context (currency, locale, market, channel) is folded into the ETag
100
+ # so a revalidation never 304s across contexts; Last-Modified mirrors
101
+ # the resource's own timestamp as before.
77
102
  stale?(
78
- etag: [resource, cache_channel_fragment],
103
+ etag: [resource, current_currency, current_locale, cache_market_fragment, cache_channel_fragment],
79
104
  last_modified: resource.try(:updated_at),
80
105
  public: true
81
106
  )
@@ -84,7 +109,7 @@ module Spree
84
109
  private
85
110
 
86
111
  # Build a cache key for a collection
87
- # Includes: latest updated_at, total count, query params, pagination, expand, currency, locale, channel
112
+ # Includes: latest updated_at, total count, query params, pagination, expand, currency, locale, market, channel
88
113
  def collection_cache_key(collection)
89
114
  # For ActiveRecord collections use updated_at, for plain arrays use store's updated_at as proxy
90
115
  latest_updated_at = if collection.first&.respond_to?(:updated_at)
@@ -103,12 +128,20 @@ module Spree
103
128
  params[:limit],
104
129
  current_currency,
105
130
  current_locale,
131
+ cache_market_fragment,
106
132
  cache_channel_fragment
107
133
  ]
108
134
 
109
135
  parts.compact.join('/')
110
136
  end
111
137
 
138
+ # Identifies the resolved market (from X-Spree-Country / ?country=).
139
+ # The market drives tax display and availability as well as currency,
140
+ # so it is part of the guest cache identity.
141
+ def cache_market_fragment
142
+ Spree::Current.market&.id
143
+ end
144
+
112
145
  # Identifies the resolved channel for cache-key purposes. The channel
113
146
  # changes the serialized body (price hiding + channel-scoped visibility),
114
147
  # so it must be part of the guest cache identity. Uses the same
@@ -29,6 +29,8 @@ module Spree
29
29
  return
30
30
  end
31
31
 
32
+ return yield if caller_identity.nil?
33
+
32
34
  cache_key = idempotency_cache_key(key)
33
35
  cached = Rails.cache.read(cache_key)
34
36
 
@@ -36,7 +38,7 @@ module Spree
36
38
  if cached[:fingerprint] != request_fingerprint
37
39
  render_error(
38
40
  code: ErrorHandler::ERROR_CODES[:idempotency_key_reused],
39
- message: Spree.t(:idempotency_key_reused),
41
+ message: I18n.t('spree.idempotency_key_reused'),
40
42
  status: :unprocessable_content
41
43
  )
42
44
  return
@@ -66,17 +68,30 @@ module Spree
66
68
  MUTATING_METHODS.include?(request.method)
67
69
  end
68
70
 
71
+ def caller_identity
72
+ return @caller_identity if defined?(@caller_identity)
73
+
74
+ credentials = []
75
+
76
+ credentials << ['secret_key', Spree::ApiKey.compute_token_digest(extract_api_key)] if secret_key_request?
77
+
78
+ bearer_token = extract_token
79
+ credentials << ['bearer', Digest::SHA256.hexdigest(bearer_token)] if bearer_token.present?
80
+
81
+ credentials << ['order_token', Digest::SHA256.hexdigest(order_token)] if order_token.present?
82
+
83
+ @caller_identity = credentials.presence
84
+ end
85
+
69
86
  def idempotency_cache_key(key)
70
- credential = request.headers['X-Spree-Api-Key'].presence ||
71
- spree_current_user&.id ||
72
- request.remote_ip
73
87
  # The resolved store partitions the namespace: a staff JWT spans
74
88
  # stores, and replaying one store's cached response for a request
75
89
  # aimed at another would cross store boundaries. The resolved
76
90
  # store — not the raw header — so a header naming the default store
77
91
  # and no header at all land in the same partition, as they resolve
78
92
  # to the same store.
79
- "spree:idempotency:#{Digest::SHA256.hexdigest("#{credential}\0#{current_store&.id}\0#{key}")}"
93
+ digest = Digest::SHA256.hexdigest([*caller_identity.flatten, current_store&.id, key].join("\0"))
94
+ "spree:idempotency:#{digest}"
80
95
  end
81
96
 
82
97
  def request_fingerprint
@@ -45,7 +45,7 @@ module Spree
45
45
  # `return_line_items`).
46
46
  def render_invalid_items
47
47
  errors = ActiveModel::Errors.new(@resource || model_class.new)
48
- errors.add(:base, :invalid_items, message: Spree.t('errors.messages.items_not_a_list'))
48
+ errors.add(:base, :invalid_items, message: I18n.t('spree.errors.messages.items_not_a_list'))
49
49
  render_validation_error(errors)
50
50
  end
51
51
  end
@@ -29,7 +29,7 @@ module Spree
29
29
  if order.is_a?(Spree::Cart) && order.completion_claimed?
30
30
  next render_error(
31
31
  code: 'completion_in_progress',
32
- message: Spree.t(:cart_completion_in_progress),
32
+ message: I18n.t('spree.cart_completion_in_progress'),
33
33
  status: :conflict
34
34
  )
35
35
  end
@@ -51,7 +51,7 @@ module Spree
51
51
  Rails.error.report(exception, context: { order_id: (@order || @parent || @cart)&.id }, source: 'spree.api.v3')
52
52
  render_error(
53
53
  code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:cart_already_updated],
54
- message: Spree.t(:cart_already_updated),
54
+ message: I18n.t('spree.cart_already_updated'),
55
55
  status: :conflict
56
56
  )
57
57
  end
@@ -28,11 +28,7 @@ module Spree
28
28
  **resource_permitted_attributes.index_with { |key| delivery_params[key] }
29
29
  )
30
30
 
31
- if result.success?
32
- render json: serialize_resource(result.value), status: :created
33
- else
34
- render_result_error(result)
35
- end
31
+ render_result(result, status: :created)
36
32
  end
37
33
  end
38
34
 
@@ -45,11 +45,7 @@ module Spree
45
45
  **fulfill_workflow_options
46
46
  )
47
47
 
48
- if result.success?
49
- render json: serialize_resource(result.value)
50
- else
51
- render_result_error(result)
52
- end
48
+ render_result(result)
53
49
  end
54
50
  end
55
51
 
@@ -60,11 +56,7 @@ module Spree
60
56
  with_order_lock do
61
57
  result = Spree.fulfillment_cancel_workflow.call(fulfillment: @resource)
62
58
 
63
- if result.success?
64
- render json: serialize_resource(result.value)
65
- else
66
- render_result_error(result)
67
- end
59
+ render_result(result)
68
60
  end
69
61
  end
70
62
 
@@ -28,11 +28,7 @@ module Spree
28
28
  def run_workflow(workflow, **arguments)
29
29
  result = workflow.call(workflow_record_key => @resource, **arguments)
30
30
 
31
- if result.success?
32
- render json: serialize_resource(result.value)
33
- else
34
- render_result_error(result)
35
- end
31
+ render_result(result)
36
32
  end
37
33
 
38
34
  # @return [Symbol] the keyword this entity's workflows take it under
@@ -63,11 +59,7 @@ module Spree
63
59
  **arguments
64
60
  )
65
61
 
66
- if result.success?
67
- render json: serialize_resource(result.value), status: :created
68
- else
69
- render_result_error(result)
70
- end
62
+ render_result(result, status: :created)
71
63
  end
72
64
  end
73
65
  end
@@ -31,7 +31,7 @@ module Spree
31
31
  stream_shipping_label(@resource) do
32
32
  render_error(
33
33
  code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:validation_error],
34
- message: Spree.t('shipping_labels.errors.no_file_url'),
34
+ message: I18n.t('spree.shipping_labels.errors.no_file_url'),
35
35
  status: :unprocessable_content
36
36
  )
37
37
  end
@@ -45,7 +45,7 @@ module Spree
45
45
  unless @resource.uploaded?
46
46
  return render_error(
47
47
  code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:validation_error],
48
- message: Spree.t('shipping_labels.errors.purchased_not_deletable'),
48
+ message: I18n.t('spree.shipping_labels.errors.purchased_not_deletable'),
49
49
  status: :unprocessable_content
50
50
  )
51
51
  end
@@ -104,11 +104,7 @@ module Spree
104
104
  **label_permitted_keys.index_with { |key| label_params[key] }
105
105
  )
106
106
 
107
- if result.success?
108
- render json: serialize_resource(result.value), status: :created
109
- else
110
- render_result_error(result)
111
- end
107
+ render_result(result, status: :created)
112
108
  end
113
109
  end
114
110
 
@@ -117,7 +113,7 @@ module Spree
117
113
  def render_invalid_signature
118
114
  render_error(
119
115
  code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:parameter_invalid],
120
- message: Spree.t('shipping_labels.errors.file_required'),
116
+ message: I18n.t('spree.shipping_labels.errors.file_required'),
121
117
  status: :unprocessable_content
122
118
  )
123
119
  end
@@ -6,6 +6,7 @@ module Spree
6
6
  # branches answer different audiences, but the frontend permission model
7
7
  # is one implementation, so its input has to be too.
8
8
  #
9
+ # - Subjects are short names (`product`), not Ruby class names.
9
10
  # - Rule order is preserved so the frontend matcher can apply
10
11
  # CanCanCan's "last matching rule wins" semantics.
11
12
  # - Per-record conditions are NOT serialized (they often reference
@@ -23,12 +24,19 @@ module Spree
23
24
  {
24
25
  allow: rule.base_behavior,
25
26
  actions: Array(rule.actions).map(&:to_s),
26
- subjects: Array(rule.subjects).map { |subject| subject.is_a?(Class) ? subject.name : subject.to_s },
27
+ subjects: Array(rule.subjects).map { |subject| serialize_subject(subject) },
27
28
  has_conditions: rule_has_conditions?(rule)
28
29
  }
29
30
  end
30
31
  end
31
32
 
33
+ # A model subject travels as its short name (`product`, `customer`),
34
+ # never the Ruby class; `all` and symbol subjects (`dashboard`) pass
35
+ # through as they are.
36
+ def serialize_subject(subject)
37
+ subject.is_a?(Class) ? Spree::Base.polymorphic_api_type(subject.name) : subject.to_s
38
+ end
39
+
32
40
  def serialize_permission_keys(ability)
33
41
  ability.respond_to?(:permission_keys) ? ability.permission_keys : []
34
42
  end
@@ -96,7 +96,7 @@ module Spree
96
96
 
97
97
  render_error(
98
98
  code: ErrorHandler::ERROR_CODES[:access_denied],
99
- message: Spree.t(:seller_access_denied),
99
+ message: I18n.t('spree.seller_access_denied'),
100
100
  status: :forbidden
101
101
  )
102
102
  false
@@ -5,9 +5,10 @@ module Spree
5
5
  # The products a storefront buyer may see: available now (or on
6
6
  # pre-order) in the current currency, narrowed to the catalogs their
7
7
  # company, customer group or channel resolve to. The product listing
8
- # reads through it, and so does anything else that accepts a product
9
- # or variant from the buyer, so an id cannot reach what the listing
10
- # would never show.
8
+ # and wishlist items read through it, so an id cannot reach what the
9
+ # listing would never show. Carts narrow through
10
+ # {Spree::Cart#orderable_variants} instead, which asks the same
11
+ # catalogs about the cart's own buyer and company.
11
12
  module StorefrontProducts
12
13
  extend ActiveSupport::Concern
13
14
 
@@ -26,7 +27,7 @@ module Spree
26
27
 
27
28
  # @return [ActiveRecord::Relation<Spree::Variant>]
28
29
  def storefront_variants
29
- Spree::Variant.where(product_id: storefront_products.reorder(nil).select(Spree::Product.arel_table[:id]))
30
+ Spree::Variant.for_products(storefront_products)
30
31
  end
31
32
  end
32
33
  end