spree_core 6.0.0.beta4 → 6.0.0.rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (575) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -5
  3. data/app/helpers/spree/images_helper.rb +0 -57
  4. data/app/jobs/spree/base_job.rb +21 -0
  5. data/app/jobs/spree/carts/reap_expired_job.rb +2 -2
  6. data/app/jobs/spree/collections/regenerate_time_based_job.rb +6 -3
  7. data/app/jobs/spree/orders/finalize_stale_drafts_job.rb +8 -5
  8. data/app/jobs/spree/payments/cancel_unused_sessions_job.rb +61 -0
  9. data/app/jobs/spree/search_provider/index_job.rb +4 -0
  10. data/app/jobs/spree/seller_payouts/sweep_seller_job.rb +2 -0
  11. data/app/jobs/spree/uploads/purge_unattached_job.rb +49 -0
  12. data/app/mailers/spree/admin_user_mailer.rb +4 -19
  13. data/app/mailers/spree/base_mailer.rb +97 -13
  14. data/app/mailers/spree/email_template_mailer.rb +27 -0
  15. data/app/mailers/spree/export_mailer.rb +3 -4
  16. data/app/mailers/spree/import_mailer.rb +3 -4
  17. data/app/mailers/spree/invitation_mailer.rb +24 -7
  18. data/app/mailers/spree/seller_user_mailer.rb +4 -16
  19. data/app/mailers/spree/webhook_mailer.rb +2 -2
  20. data/app/models/concerns/spree/acted_by.rb +1 -1
  21. data/app/models/concerns/spree/admin_user_methods.rb +15 -1
  22. data/app/models/concerns/spree/api_typed.rb +91 -0
  23. data/app/models/concerns/spree/calculated_adjustments.rb +41 -13
  24. data/app/models/concerns/spree/calculator/currency_amounts.rb +1 -1
  25. data/app/models/concerns/spree/calculator/tiers.rb +63 -0
  26. data/app/models/concerns/spree/canonical_decimals.rb +61 -0
  27. data/app/models/concerns/spree/customer_methods.rb +23 -18
  28. data/app/models/concerns/spree/derived_number.rb +11 -13
  29. data/app/models/concerns/spree/email_template_identity.rb +52 -0
  30. data/app/models/concerns/spree/parameterizable_name.rb +2 -0
  31. data/app/models/concerns/spree/payment_session_transitions.rb +8 -2
  32. data/app/models/concerns/spree/post_sale/taxation.rb +54 -0
  33. data/app/models/concerns/spree/post_sale/taxed_line.rb +51 -0
  34. data/app/models/concerns/spree/preference_schema/json_schema.rb +139 -0
  35. data/app/models/concerns/spree/preference_schema.rb +62 -32
  36. data/app/models/concerns/spree/product_scopes.rb +16 -2
  37. data/app/models/concerns/spree/provider_listing.rb +41 -0
  38. data/app/models/concerns/spree/publishable.rb +82 -14
  39. data/app/models/concerns/spree/purchase/addresses.rb +23 -10
  40. data/app/models/concerns/spree/purchase/currency.rb +1 -1
  41. data/app/models/concerns/spree/purchase/deprecated_aliases.rb +87 -0
  42. data/app/models/concerns/spree/purchase/gift_cards.rb +10 -4
  43. data/app/models/concerns/spree/purchase/locale.rb +1 -1
  44. data/app/models/concerns/spree/purchase/payment_processing.rb +8 -4
  45. data/app/models/concerns/spree/purchase/purchase_order.rb +9 -4
  46. data/app/models/concerns/spree/purchase/store_credits.rb +36 -1
  47. data/app/models/concerns/spree/purchase/totals.rb +49 -8
  48. data/app/models/concerns/spree/ransackable_attributes.rb +46 -0
  49. data/app/models/concerns/spree/receivable.rb +1 -1
  50. data/app/models/concerns/spree/searchable.rb +0 -4
  51. data/app/models/concerns/spree/secret_preferences.rb +59 -0
  52. data/app/models/concerns/spree/signed_id_attachments.rb +54 -0
  53. data/app/models/concerns/spree/single_store_resource.rb +1 -1
  54. data/app/models/concerns/spree/stores/email_branding.rb +32 -0
  55. data/app/models/concerns/spree/stores/markets.rb +5 -2
  56. data/app/models/concerns/spree/type_labels.rb +38 -0
  57. data/app/models/concerns/spree/typed_adjustment_line.rb +5 -6
  58. data/app/models/concerns/spree/typed_associations.rb +12 -18
  59. data/app/models/concerns/spree/vat_price_calculation.rb +5 -6
  60. data/app/models/spree/address.rb +12 -2
  61. data/app/models/spree/adjusters/largest_remainder.rb +14 -1
  62. data/app/models/spree/adjusters/promotion.rb +4 -19
  63. data/app/models/spree/allowed_origin.rb +3 -1
  64. data/app/models/spree/api_key.rb +5 -6
  65. data/app/models/spree/authentication/strategies/oidc_strategy.rb +5 -5
  66. data/app/models/spree/base.rb +99 -22
  67. data/app/models/spree/calculator/flat_percent_item_total.rb +2 -4
  68. data/app/models/spree/calculator/flat_rate.rb +3 -5
  69. data/app/models/spree/calculator/flexi_rate.rb +4 -6
  70. data/app/models/spree/calculator/percent_on_line_item.rb +2 -2
  71. data/app/models/spree/calculator/price_sack.rb +5 -7
  72. data/app/models/spree/calculator/shipping/digital_delivery.rb +3 -5
  73. data/app/models/spree/calculator/shipping/flat_percent_item_total.rb +7 -7
  74. data/app/models/spree/calculator/shipping/flat_rate.rb +5 -7
  75. data/app/models/spree/calculator/shipping/flexi_rate.rb +4 -6
  76. data/app/models/spree/calculator/shipping/per_item.rb +3 -5
  77. data/app/models/spree/calculator/shipping/price_sack.rb +5 -7
  78. data/app/models/spree/calculator/tiered_flat_rate.rb +7 -24
  79. data/app/models/spree/calculator/tiered_percent.rb +7 -25
  80. data/app/models/spree/cart.rb +78 -18
  81. data/app/models/spree/catalog.rb +1 -0
  82. data/app/models/spree/catalog_price.rb +0 -7
  83. data/app/models/spree/catalog_price_tier.rb +0 -8
  84. data/app/models/spree/category.rb +3 -1
  85. data/app/models/spree/channel/gating.rb +3 -2
  86. data/app/models/spree/channel.rb +6 -4
  87. data/app/models/spree/claim.rb +22 -1
  88. data/app/models/spree/claim_line_item.rb +41 -6
  89. data/app/models/spree/collection.rb +2 -1
  90. data/app/models/spree/collection_rule.rb +5 -21
  91. data/app/models/spree/commission_line.rb +1 -1
  92. data/app/models/spree/commission_rate.rb +7 -4
  93. data/app/models/spree/commission_rate_value.rb +1 -1
  94. data/app/models/spree/commission_rule.rb +4 -11
  95. data/app/models/spree/commission_rules/category_rule.rb +2 -5
  96. data/app/models/spree/commission_rules/item_total_rule.rb +2 -2
  97. data/app/models/spree/commission_rules/product_rule.rb +1 -1
  98. data/app/models/spree/commission_rules/seller_rule.rb +2 -5
  99. data/app/models/spree/company.rb +1 -0
  100. data/app/models/spree/company_invitation.rb +1 -0
  101. data/app/models/spree/consent_record.rb +0 -1
  102. data/app/models/spree/credit_card.rb +1 -1
  103. data/app/models/spree/current.rb +23 -0
  104. data/app/models/spree/custom_field.rb +2 -2
  105. data/app/models/spree/custom_field_definition.rb +20 -35
  106. data/app/models/spree/custom_fields/boolean.rb +1 -1
  107. data/app/models/spree/custom_fields/json.rb +1 -1
  108. data/app/models/spree/customer_group.rb +1 -0
  109. data/app/models/spree/data_feed/google.rb +0 -2
  110. data/app/models/spree/data_request.rb +2 -1
  111. data/app/models/spree/delivery_method.rb +36 -14
  112. data/app/models/spree/delivery_method_rule.rb +4 -11
  113. data/app/models/spree/delivery_method_rules/channel_rule.rb +2 -5
  114. data/app/models/spree/delivery_method_rules/item_total_rule.rb +2 -2
  115. data/app/models/spree/delivery_profile.rb +1 -0
  116. data/app/models/spree/delivery_rate.rb +7 -8
  117. data/app/models/spree/delivery_rate_provider/base.rb +1 -0
  118. data/app/models/spree/delivery_zone.rb +1 -2
  119. data/app/models/spree/delivery_zone_member.rb +4 -4
  120. data/app/models/spree/digital_asset.rb +7 -0
  121. data/app/models/spree/digital_asset_provider/base.rb +2 -0
  122. data/app/models/spree/digital_link.rb +2 -5
  123. data/app/models/spree/discount.rb +1 -1
  124. data/app/models/spree/email_template.rb +25 -0
  125. data/app/models/spree/email_template_draft.rb +13 -0
  126. data/app/models/spree/email_template_revision.rb +17 -0
  127. data/app/models/spree/email_templates/entry.rb +118 -0
  128. data/app/models/spree/email_templates/sample_record.rb +16 -0
  129. data/app/models/spree/emails/branding.rb +80 -0
  130. data/app/models/spree/exchange.rb +16 -1
  131. data/app/models/spree/exchange_line_item.rb +121 -5
  132. data/app/models/spree/export.rb +0 -1
  133. data/app/models/spree/exports/products.rb +10 -1
  134. data/app/models/spree/exports/report.rb +3 -3
  135. data/app/models/spree/fee.rb +4 -2
  136. data/app/models/spree/file_upload.rb +155 -0
  137. data/app/models/spree/fulfillment.rb +66 -30
  138. data/app/models/spree/fulfillment_changer.rb +2 -2
  139. data/app/models/spree/fulfillment_group.rb +6 -1
  140. data/app/models/spree/fulfillment_item.rb +0 -4
  141. data/app/models/spree/fulfillment_provider/base.rb +1 -0
  142. data/app/models/spree/gateway/bogus.rb +6 -0
  143. data/app/models/spree/gateway/custom_payment_source_method.rb +5 -0
  144. data/app/models/spree/gateway.rb +6 -2
  145. data/app/models/spree/gift_card.rb +18 -8
  146. data/app/models/spree/gift_card_batch.rb +3 -5
  147. data/app/models/spree/import.rb +5 -7
  148. data/app/models/spree/import_mapping.rb +1 -2
  149. data/app/models/spree/import_row.rb +2 -2
  150. data/app/models/spree/import_schemas/products.rb +1 -0
  151. data/app/models/spree/integration.rb +9 -19
  152. data/app/models/spree/invitation.rb +5 -5
  153. data/app/models/spree/line_item.rb +15 -4
  154. data/app/models/spree/locale.rb +11 -8
  155. data/app/models/spree/market.rb +8 -2
  156. data/app/models/spree/media.rb +1 -9
  157. data/app/models/spree/newsletter_subscriber.rb +4 -0
  158. data/app/models/spree/option_type.rb +2 -1
  159. data/app/models/spree/option_value.rb +2 -1
  160. data/app/models/spree/order.rb +60 -142
  161. data/app/models/spree/order_group.rb +18 -4
  162. data/app/models/spree/order_inventory.rb +10 -5
  163. data/app/models/spree/order_promotion.rb +1 -1
  164. data/app/models/spree/order_routing/has_strategy_preference.rb +1 -1
  165. data/app/models/spree/order_routing/strategy/base.rb +4 -2
  166. data/app/models/spree/order_routing/strategy/rules.rb +1 -1
  167. data/app/models/spree/order_routing_rule.rb +6 -22
  168. data/app/models/spree/package_type.rb +2 -2
  169. data/app/models/spree/payment/gateway_options.rb +15 -53
  170. data/app/models/spree/payment/processing.rb +2 -4
  171. data/app/models/spree/payment.rb +21 -13
  172. data/app/models/spree/payment_method/check.rb +2 -0
  173. data/app/models/spree/payment_method/session_instrumentation.rb +1 -0
  174. data/app/models/spree/payment_method/store_credit.rb +15 -13
  175. data/app/models/spree/payment_method.rb +78 -6
  176. data/app/models/spree/payment_session.rb +5 -1
  177. data/app/models/spree/payment_setup_session.rb +1 -0
  178. data/app/models/spree/payout_provider/base.rb +3 -1
  179. data/app/models/spree/pickup_point_provider/base.rb +2 -0
  180. data/app/models/spree/policy.rb +1 -0
  181. data/app/models/spree/price.rb +17 -14
  182. data/app/models/spree/price_adjustment_tier.rb +4 -0
  183. data/app/models/spree/price_list.rb +14 -9
  184. data/app/models/spree/price_rules/channel_rule.rb +3 -6
  185. data/app/models/spree/price_rules/customer_group_rule.rb +3 -6
  186. data/app/models/spree/price_rules/market_rule.rb +2 -5
  187. data/app/models/spree/price_rules/user_rule.rb +1 -3
  188. data/app/models/spree/product/channels.rb +9 -2
  189. data/app/models/spree/product.rb +54 -30
  190. data/app/models/spree/product_submission.rb +0 -12
  191. data/app/models/spree/product_type.rb +1 -1
  192. data/app/models/spree/promotion/actions/create_line_items.rb +28 -18
  193. data/app/models/spree/promotion/rules/category.rb +1 -5
  194. data/app/models/spree/promotion/rules/channel.rb +2 -9
  195. data/app/models/spree/promotion/rules/country.rb +3 -8
  196. data/app/models/spree/promotion/rules/currency.rb +1 -5
  197. data/app/models/spree/promotion/rules/customer_group.rb +2 -9
  198. data/app/models/spree/promotion/rules/first_order.rb +0 -4
  199. data/app/models/spree/promotion/rules/item_total.rb +6 -10
  200. data/app/models/spree/promotion/rules/market.rb +2 -9
  201. data/app/models/spree/promotion/rules/one_use_per_user.rb +0 -4
  202. data/app/models/spree/promotion/rules/option_value.rb +2 -6
  203. data/app/models/spree/promotion/rules/product.rb +1 -5
  204. data/app/models/spree/promotion/rules/user.rb +0 -4
  205. data/app/models/spree/promotion/rules/user_logged_in.rb +0 -4
  206. data/app/models/spree/promotion.rb +36 -6
  207. data/app/models/spree/promotion_action.rb +7 -14
  208. data/app/models/spree/promotion_action_line_item.rb +1 -1
  209. data/app/models/spree/promotion_handler/coupon.rb +59 -27
  210. data/app/models/spree/promotion_rule.rb +7 -14
  211. data/app/models/spree/purchase_order.rb +3 -0
  212. data/app/models/spree/quantity_rule.rb +1 -1
  213. data/app/models/spree/refund.rb +41 -18
  214. data/app/models/spree/return.rb +31 -2
  215. data/app/models/spree/return_line_item.rb +65 -14
  216. data/app/models/spree/role.rb +7 -7
  217. data/app/models/spree/saved_report.rb +2 -1
  218. data/app/models/spree/search_provider/base.rb +4 -0
  219. data/app/models/spree/seller.rb +10 -2
  220. data/app/models/spree/seller_payout.rb +8 -0
  221. data/app/models/spree/seller_requirement.rb +5 -12
  222. data/app/models/spree/seller_requirement_custom_field.rb +1 -2
  223. data/app/models/spree/seller_requirement_submission.rb +3 -2
  224. data/app/models/spree/seller_requirements/accept_terms.rb +2 -3
  225. data/app/models/spree/seller_transfer.rb +6 -0
  226. data/app/models/spree/shipping_label.rb +2 -0
  227. data/app/models/spree/stock/availability_validator.rb +2 -2
  228. data/app/models/spree/stock/estimator.rb +1 -1
  229. data/app/models/spree/stock/inventory_unit_builder.rb +1 -1
  230. data/app/models/spree/stock/packer.rb +2 -2
  231. data/app/models/spree/stock/splitter/weight.rb +1 -1
  232. data/app/models/spree/stock_level/custom_events.rb +6 -0
  233. data/app/models/spree/stock_level.rb +3 -1
  234. data/app/models/spree/stock_location.rb +1 -0
  235. data/app/models/spree/stock_movement.rb +1 -1
  236. data/app/models/spree/stock_receipt_item.rb +1 -1
  237. data/app/models/spree/stock_reservation.rb +2 -2
  238. data/app/models/spree/stock_transfer.rb +6 -2
  239. data/app/models/spree/store.rb +70 -19
  240. data/app/models/spree/store_credit.rb +13 -13
  241. data/app/models/spree/store_credit_event.rb +5 -5
  242. data/app/models/spree/supplier.rb +1 -0
  243. data/app/models/spree/tax_category.rb +1 -0
  244. data/app/models/spree/tax_exemption_certificate.rb +3 -0
  245. data/app/models/spree/tax_identifier.rb +3 -1
  246. data/app/models/spree/tax_line.rb +53 -3
  247. data/app/models/spree/tax_provider/base.rb +71 -14
  248. data/app/models/spree/tax_provider/internal.rb +70 -41
  249. data/app/models/spree/tax_provider/recorded_share.rb +114 -0
  250. data/app/models/spree/tax_rate.rb +30 -8
  251. data/app/models/spree/taxon.rb +1 -1
  252. data/app/models/spree/taxonomy.rb +0 -1
  253. data/app/models/spree/update_status.rb +25 -0
  254. data/app/models/spree/variant.rb +10 -12
  255. data/app/models/spree/variant_media.rb +1 -1
  256. data/app/models/spree/webhook_delivery.rb +1 -0
  257. data/app/models/spree/webhook_endpoint.rb +46 -13
  258. data/app/models/spree/wishlist.rb +1 -6
  259. data/app/models/spree/wishlist_item/custom_events.rb +6 -0
  260. data/app/presenters/spree/csv/customer_presenter.rb +1 -1
  261. data/app/presenters/spree/csv/newsletter_subscriber_presenter.rb +1 -1
  262. data/app/presenters/spree/csv/order_line_item_presenter.rb +10 -6
  263. data/app/presenters/spree/csv/price_list_price_presenter.rb +3 -8
  264. data/app/presenters/spree/csv/product_variant_presenter.rb +59 -20
  265. data/app/presenters/spree/csv/purchase_order_item_presenter.rb +1 -3
  266. data/app/serializers/spree/emails/base_serializer.rb +14 -0
  267. data/app/serializers/spree/emails/export_serializer.rb +13 -0
  268. data/app/serializers/spree/emails/import_serializer.rb +19 -0
  269. data/app/serializers/spree/emails/invitation_serializer.rb +28 -0
  270. data/app/serializers/spree/emails/store_serializer.rb +31 -0
  271. data/app/serializers/spree/emails/user_serializer.rb +12 -0
  272. data/app/serializers/spree/emails/webhook_endpoint_serializer.rb +16 -0
  273. data/app/services/spree/carts/create.rb +8 -2
  274. data/app/services/spree/carts/destroy.rb +2 -2
  275. data/app/services/spree/carts/remove_out_of_stock_items.rb +2 -2
  276. data/app/services/spree/carts/split_by_seller.rb +1 -1
  277. data/app/services/spree/carts/update.rb +22 -8
  278. data/app/services/spree/catalogs/set_product_terms.rb +1 -1
  279. data/app/services/spree/categories/add_products.rb +13 -31
  280. data/app/services/spree/categories/remove_products.rb +12 -51
  281. data/app/services/spree/checkout/advance.rb +1 -4
  282. data/app/services/spree/collections/add_products.rb +10 -23
  283. data/app/services/spree/collections/remove_products.rb +7 -43
  284. data/app/services/spree/coupon_codes/bulk_generate.rb +8 -14
  285. data/app/services/spree/data_requests/create.rb +1 -1
  286. data/app/services/spree/deliveries/destroy.rb +2 -2
  287. data/app/services/spree/email_templates/check.rb +58 -0
  288. data/app/services/spree/email_templates/no_sample_record.rb +7 -0
  289. data/app/services/spree/email_templates/preview.rb +99 -0
  290. data/app/services/spree/emails/file_system.rb +23 -0
  291. data/app/services/spree/emails/filters.rb +84 -0
  292. data/app/services/spree/emails/liquid_context.rb +48 -0
  293. data/app/services/spree/emails/rendered_email.rb +14 -0
  294. data/app/services/spree/emails/renderer.rb +125 -0
  295. data/app/services/spree/emails/template.rb +51 -0
  296. data/app/services/spree/emails/template_data.rb +23 -0
  297. data/app/services/spree/emails/template_resolver.rb +109 -0
  298. data/app/services/spree/emails/text_converter.rb +72 -0
  299. data/app/services/spree/emails/translation_inliner.rb +134 -0
  300. data/app/services/spree/imports/row_processors/price_list_price.rb +10 -10
  301. data/app/services/spree/imports/row_processors/product_variant.rb +77 -34
  302. data/app/services/spree/imports/row_processors/purchase_order.rb +13 -13
  303. data/app/services/spree/locales.rb +43 -10
  304. data/app/services/spree/newsletter/subscribe.rb +8 -12
  305. data/app/services/spree/orders/build_fulfillments.rb +3 -2
  306. data/app/services/spree/orders/create.rb +5 -4
  307. data/app/services/spree/orders/discounts/create.rb +14 -11
  308. data/app/services/spree/orders/discounts/destroy.rb +1 -0
  309. data/app/services/spree/orders/discounts/update.rb +1 -0
  310. data/app/services/spree/orders/fees/create.rb +1 -0
  311. data/app/services/spree/orders/fees/destroy.rb +1 -0
  312. data/app/services/spree/orders/fees/update.rb +1 -0
  313. data/app/services/spree/orders/remove_line_item.rb +13 -3
  314. data/app/services/spree/orders/update.rb +10 -6
  315. data/app/services/spree/orders/update_item.rb +6 -3
  316. data/app/services/spree/orders/update_statuses.rb +3 -1
  317. data/app/services/spree/prices/bulk_upsert.rb +32 -25
  318. data/app/services/spree/product_memberships.rb +61 -0
  319. data/app/services/spree/returns/eligibility_validator.rb +1 -1
  320. data/app/services/spree/search_provider/custom_field_schema.rb +2 -2
  321. data/app/services/spree/seeds/commission_rates.rb +1 -1
  322. data/app/services/spree/seeds/digital_delivery.rb +1 -1
  323. data/app/services/spree/seeds/payment_methods.rb +2 -2
  324. data/app/services/spree/seeds/saved_reports.rb +3 -3
  325. data/app/services/spree/seeds/stores.rb +1 -1
  326. data/app/services/spree/sellers/requirements.rb +1 -2
  327. data/app/services/spree/shipping_labels/confirm_refund.rb +1 -1
  328. data/app/services/spree/shipping_labels/store_file.rb +3 -3
  329. data/app/services/spree/stock_levels/correct.rb +3 -3
  330. data/app/services/spree/stock_reservations/reserve.rb +2 -3
  331. data/app/services/spree/store_credits/apply.rb +15 -13
  332. data/app/services/spree/stores/provision_defaults.rb +23 -25
  333. data/app/services/spree/update_check.rb +160 -0
  334. data/app/services/spree/uploads/assign_stores.rb +92 -0
  335. data/app/subscribers/spree/seller_onboarding_subscriber.rb +1 -1
  336. data/app/validators/spree/attachment_content_type_validator.rb +19 -2
  337. data/app/validators/spree/locale_codes_validator.rb +22 -0
  338. data/app/views/layouts/spree/base_mailer.html.erb +2 -43
  339. data/app/views/layouts/spree/base_mailer.liquid +79 -0
  340. data/app/views/spree/admin_user_mailer/password_reset_email.liquid +14 -0
  341. data/app/views/spree/export_mailer/export_done.liquid +12 -0
  342. data/app/views/spree/import_mailer/import_done.liquid +15 -0
  343. data/app/views/spree/invitation_mailer/invitation_accepted.liquid +9 -0
  344. data/app/views/spree/invitation_mailer/invitation_email.liquid +13 -0
  345. data/app/views/spree/seller_user_mailer/password_reset_email.liquid +14 -0
  346. data/app/views/spree/shared/_mailer_button.html.erb +4 -5
  347. data/app/views/spree/shared/_mailer_hero.html.erb +6 -5
  348. data/app/views/spree/shared/_summary_row.liquid +8 -0
  349. data/app/views/spree/webhook_mailer/endpoint_disabled.liquid +21 -0
  350. data/app/workflows/spree/carts/add_item.rb +4 -4
  351. data/app/workflows/spree/carts/complete.rb +13 -3
  352. data/app/workflows/spree/carts/merge.rb +1 -1
  353. data/app/workflows/spree/carts/recalculate_totals.rb +5 -0
  354. data/app/workflows/spree/carts/upsert_items.rb +18 -9
  355. data/app/workflows/spree/claims/approve.rb +5 -22
  356. data/app/workflows/spree/claims/cancel.rb +5 -21
  357. data/app/workflows/spree/claims/create.rb +15 -0
  358. data/app/workflows/spree/claims/deny.rb +7 -0
  359. data/app/workflows/spree/claims/resolve.rb +34 -31
  360. data/app/workflows/spree/customers/anonymize.rb +3 -4
  361. data/app/workflows/spree/customers/create.rb +1 -1
  362. data/app/workflows/spree/data_requests/fulfill.rb +2 -2
  363. data/app/workflows/spree/deliveries/update_tracking.rb +1 -1
  364. data/app/workflows/spree/email_templates/discard_draft.rb +20 -0
  365. data/app/workflows/spree/email_templates/publish.rb +70 -0
  366. data/app/workflows/spree/email_templates/restore_revision.rb +33 -0
  367. data/app/workflows/spree/email_templates/revert.rb +29 -0
  368. data/app/workflows/spree/email_templates/save_draft.rb +85 -0
  369. data/app/workflows/spree/exchanges/approve.rb +5 -22
  370. data/app/workflows/spree/exchanges/cancel.rb +5 -21
  371. data/app/workflows/spree/exchanges/create.rb +6 -0
  372. data/app/workflows/spree/exchanges/fulfill.rb +75 -51
  373. data/app/workflows/spree/exchanges/receive.rb +6 -65
  374. data/app/workflows/spree/fulfillments/cancel.rb +1 -1
  375. data/app/workflows/spree/fulfillments/create.rb +53 -49
  376. data/app/workflows/spree/fulfillments/fulfill.rb +23 -27
  377. data/app/workflows/spree/fulfillments/mark_delivered.rb +1 -1
  378. data/app/workflows/spree/fulfillments/replacements.rb +59 -0
  379. data/app/workflows/spree/gift_cards/apply.rb +2 -2
  380. data/app/workflows/spree/orders/add_item.rb +5 -1
  381. data/app/workflows/spree/orders/cancel.rb +3 -3
  382. data/app/workflows/spree/orders/complete.rb +16 -8
  383. data/app/workflows/spree/payments/capture.rb +20 -5
  384. data/app/workflows/spree/payments/process.rb +5 -3
  385. data/app/workflows/spree/post_sale/approval.rb +35 -0
  386. data/app/workflows/spree/post_sale/cancellation.rb +44 -0
  387. data/app/workflows/spree/post_sale/receipt.rb +92 -0
  388. data/app/workflows/spree/price_lists/update.rb +4 -4
  389. data/app/workflows/spree/products/nested_attributes.rb +1 -1
  390. data/app/workflows/spree/purchase_orders/cancel.rb +1 -1
  391. data/app/workflows/spree/purchase_orders/close.rb +3 -31
  392. data/app/workflows/spree/purchase_orders/create.rb +3 -1
  393. data/app/workflows/spree/purchase_orders/mark_draft.rb +2 -2
  394. data/app/workflows/spree/purchase_orders/mark_ordered.rb +2 -2
  395. data/app/workflows/spree/purchase_orders/receive.rb +1 -1
  396. data/app/workflows/spree/purchase_orders/update.rb +5 -34
  397. data/app/workflows/spree/receivables/closing_short.rb +46 -0
  398. data/app/workflows/spree/receivables/draft_editing.rb +48 -0
  399. data/app/workflows/spree/refunds/create.rb +5 -2
  400. data/app/workflows/spree/refunds/order_payments.rb +14 -2
  401. data/app/workflows/spree/refunds/tax_credit.rb +67 -0
  402. data/app/workflows/spree/returns/approve.rb +5 -22
  403. data/app/workflows/spree/returns/cancel.rb +5 -22
  404. data/app/workflows/spree/returns/create.rb +8 -0
  405. data/app/workflows/spree/returns/receive.rb +5 -76
  406. data/app/workflows/spree/returns/refund.rb +31 -8
  407. data/app/workflows/spree/seller_requirement_submissions/create.rb +1 -2
  408. data/app/workflows/spree/seller_transfers/reverse.rb +28 -1
  409. data/app/workflows/spree/shipping_labels/purchase.rb +8 -8
  410. data/app/workflows/spree/shipping_labels/record.rb +7 -7
  411. data/app/workflows/spree/shipping_labels/refund.rb +2 -2
  412. data/app/workflows/spree/stock_receipts/recording.rb +4 -4
  413. data/app/workflows/spree/stock_transfers/cancel.rb +2 -2
  414. data/app/workflows/spree/stock_transfers/close.rb +3 -30
  415. data/app/workflows/spree/stock_transfers/create.rb +3 -1
  416. data/app/workflows/spree/stock_transfers/mark_draft.rb +1 -1
  417. data/app/workflows/spree/stock_transfers/mark_in_transit.rb +3 -3
  418. data/app/workflows/spree/stock_transfers/mark_ready.rb +2 -2
  419. data/app/workflows/spree/stock_transfers/receive.rb +1 -1
  420. data/app/workflows/spree/stock_transfers/update.rb +5 -33
  421. data/config/currency_exponents.json +180 -0
  422. data/config/i18n-tasks.yml +32 -18
  423. data/config/initializers/alba.rb +7 -0
  424. data/config/language_names.csv +264 -0
  425. data/config/locales/ar.yml +811 -0
  426. data/config/locales/be.yml +855 -0
  427. data/config/locales/bg.yml +723 -0
  428. data/config/locales/ca.yml +689 -0
  429. data/config/locales/content_locales.rb +9 -0
  430. data/config/locales/cs.yml +855 -0
  431. data/config/locales/da.yml +771 -0
  432. data/config/locales/de-CH.yml +248 -0
  433. data/config/locales/de.yml +835 -0
  434. data/config/locales/el.yml +769 -0
  435. data/config/locales/en.yml +47 -505
  436. data/config/locales/es-CL.yml +301 -0
  437. data/config/locales/es-EC.yml +186 -0
  438. data/config/locales/es-MX.yml +334 -0
  439. data/config/locales/es.yml +831 -0
  440. data/config/locales/et.yml +644 -0
  441. data/config/locales/fa.yml +709 -0
  442. data/config/locales/fi.yml +771 -0
  443. data/config/locales/fr.yml +830 -0
  444. data/config/locales/hu.yml +751 -0
  445. data/config/locales/id.yml +756 -0
  446. data/config/locales/it.yml +833 -0
  447. data/config/locales/ja.yml +726 -0
  448. data/config/locales/km.yml +759 -0
  449. data/config/locales/ko.yml +575 -0
  450. data/config/locales/ku.yml +753 -0
  451. data/config/locales/lt.yml +821 -0
  452. data/config/locales/lv.yml +685 -0
  453. data/config/locales/nb.yml +824 -0
  454. data/config/locales/ne.yml +823 -0
  455. data/config/locales/nl.yml +826 -0
  456. data/config/locales/pl.yml +835 -0
  457. data/config/locales/pt-BR.yml +547 -0
  458. data/config/locales/pt.yml +636 -0
  459. data/config/locales/ro.yml +750 -0
  460. data/config/locales/ru.yml +834 -0
  461. data/config/locales/sk.yml +680 -0
  462. data/config/locales/sl-SI.yml +600 -0
  463. data/config/locales/sv.yml +827 -0
  464. data/config/locales/th.yml +745 -0
  465. data/config/locales/tr.yml +777 -0
  466. data/config/locales/uk.yml +836 -0
  467. data/config/locales/vi.yml +768 -0
  468. data/config/locales/zh-CN.yml +786 -0
  469. data/config/locales/zh-TW.yml +834 -0
  470. data/db/migrate/20260925000001_add_replacement_to_spree_fulfillment_items.rb +5 -0
  471. data/db/migrate/20261001000001_add_post_sale_tax.rb +30 -0
  472. data/db/migrate/20261001000001_convert_preferences_to_json.rb +166 -0
  473. data/db/migrate/20261001000001_create_spree_email_templates.rb +52 -0
  474. data/db/migrate/20261009000001_change_money_columns_to_decimal_19_4.rb +116 -0
  475. data/db/migrate/20261010000001_add_store_id_to_active_storage_blobs.rb +12 -0
  476. data/lib/generators/spree/dummy/dummy_generator.rb +0 -9
  477. data/lib/generators/spree/dummy/templates/rails/test.rb +26 -0
  478. data/lib/spree/checkout/default_requirements.rb +37 -13
  479. data/lib/spree/core/configuration.rb +19 -1
  480. data/lib/spree/core/controller_helpers/store.rb +1 -1
  481. data/lib/spree/core/dependencies.rb +5 -4
  482. data/lib/spree/core/emails/escaped_output.rb +60 -0
  483. data/lib/spree/core/engine.rb +72 -165
  484. data/lib/spree/core/permissions/default_catalog.rb +5 -0
  485. data/lib/spree/core/preferences/invalid_preferences.rb +18 -0
  486. data/lib/spree/core/preferences/json_conversion.rb +186 -0
  487. data/lib/spree/core/preferences/masking.rb +55 -2
  488. data/lib/spree/core/preferences/preferable.rb +343 -103
  489. data/lib/spree/core/preferences/preferable_class_methods.rb +188 -136
  490. data/lib/spree/core/previews/import_preview.rb +10 -0
  491. data/lib/spree/core/ransack_configuration.rb +13 -2
  492. data/lib/spree/core/tax/provider_error.rb +37 -0
  493. data/lib/spree/core/version.rb +1 -1
  494. data/lib/spree/core.rb +91 -373
  495. data/lib/spree/emails/editable_templates.rb +82 -0
  496. data/lib/spree/events/catalog.rb +189 -0
  497. data/lib/spree/events.rb +21 -1
  498. data/lib/spree/hooks.rb +0 -17
  499. data/lib/spree/i18n.rb +32 -15
  500. data/lib/spree/iso_data.rb +7 -0
  501. data/lib/spree/localized_number.rb +6 -0
  502. data/lib/spree/migrations.rb +4 -1
  503. data/lib/spree/money.rb +196 -15
  504. data/lib/spree/reporting/adapters/base.rb +7 -6
  505. data/lib/spree/reporting/adapters/live.rb +6 -6
  506. data/lib/spree/reporting/default_vocabulary.rb +22 -10
  507. data/lib/spree/reporting/hydration.rb +1 -1
  508. data/lib/spree/reporting/query.rb +8 -0
  509. data/lib/spree/reporting/registry.rb +13 -0
  510. data/lib/spree/reporting/schema.rb +10 -10
  511. data/lib/spree/testing_support/editable_email_templates.rb +61 -0
  512. data/lib/spree/testing_support/emails.rb +22 -0
  513. data/lib/spree/testing_support/factories/cart_factory.rb +1 -1
  514. data/lib/spree/testing_support/factories/email_template_factory.rb +28 -0
  515. data/lib/spree/testing_support/factories/order_factory.rb +2 -2
  516. data/lib/spree/testing_support/factories/product_factory.rb +9 -0
  517. data/lib/spree/testing_support/factories/refund_factory.rb +1 -1
  518. data/lib/spree/testing_support/factories/stock_factory.rb +1 -1
  519. data/lib/spree/testing_support/factories/variant_factory.rb +1 -1
  520. data/lib/spree/testing_support/i18n.rb +3 -94
  521. data/lib/spree/testing_support/lifecycle_events.rb +1 -1
  522. data/lib/spree/testing_support/order_walkthrough.rb +1 -1
  523. data/lib/spree/testing_support/preferences.rb +0 -5
  524. data/lib/spree/testing_support/store.rb +9 -1
  525. data/lib/spree/upgrades/5_6_to_6_0/manifest.yml +67 -1
  526. data/lib/spree/uploads.rb +101 -0
  527. data/lib/tasks/categories_and_collections.rake +3 -3
  528. data/lib/tasks/core.rake +6 -4
  529. data/lib/tasks/markets.rake +2 -1
  530. data/lib/tasks/media.rake +3 -3
  531. data/lib/tasks/migrate_users_to_customers.rake +23 -18
  532. data/lib/tasks/money.rake +46 -0
  533. data/lib/tasks/package_types.rake +1 -1
  534. data/lib/tasks/preferences_json.rake +101 -0
  535. data/lib/tasks/seller_sample_data.rake +2 -2
  536. data/lib/tasks/store_settings.rake +13 -6
  537. data/lib/tasks/typed_adjustments_migration.rake +1 -1
  538. data/lib/tasks/uploads.rake +19 -0
  539. data/spec/fixtures/mailer_views/custom_views_probe_mailer/welcome_email.html.erb +4 -0
  540. metadata +219 -46
  541. data/app/jobs/spree/products/touch_categories_job.rb +0 -15
  542. data/app/jobs/spree/products/touch_taxons_job.rb +0 -13
  543. data/app/models/acts_as_taggable_on/tag_decorator.rb +0 -10
  544. data/app/models/concerns/spree/has_image_alt_text.rb +0 -18
  545. data/app/models/spree/base_analytics_event_handler.rb +0 -54
  546. data/app/models/spree/invitations/store.rb +0 -6
  547. data/app/models/spree/preference.rb +0 -14
  548. data/app/models/spree/promotion_handler/page.rb +0 -25
  549. data/app/models/spree/promotion_handler/promotion_duplicator.rb +0 -60
  550. data/app/models/spree/stock/differentiator.rb +0 -45
  551. data/app/presenters/spree/filters/options_presenter.rb +0 -47
  552. data/app/services/spree/carts/empty.rb +0 -42
  553. data/app/services/spree/country_to_timezone.rb +0 -273
  554. data/app/services/spree/payments/create.rb +0 -92
  555. data/app/validators/spree/url_validator.rb +0 -23
  556. data/app/views/active_storage/blobs/_blob.html.erb +0 -14
  557. data/app/views/spree/admin_user_mailer/password_reset_email.html.erb +0 -8
  558. data/app/views/spree/export_mailer/export_done.html.erb +0 -7
  559. data/app/views/spree/import_mailer/import_done.html.erb +0 -12
  560. data/app/views/spree/invitation_mailer/invitation_accepted.html.erb +0 -4
  561. data/app/views/spree/invitation_mailer/invitation_email.html.erb +0 -12
  562. data/app/views/spree/seller_user_mailer/password_reset_email.html.erb +0 -8
  563. data/app/views/spree/shared/_base_mailer_footer.html.erb +0 -19
  564. data/app/views/spree/shared/_base_mailer_header.html.erb +0 -8
  565. data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +0 -399
  566. data/app/views/spree/shared/_mailer_logo.html.erb +0 -41
  567. data/app/views/spree/shared/_purchased_items_styles.html.erb +0 -119
  568. data/app/views/spree/webhook_mailer/endpoint_disabled.html.erb +0 -51
  569. data/app/views/spree/webhook_mailer/endpoint_disabled.text.erb +0 -10
  570. data/app/workflows/spree/fulfillments/purchase_label.rb +0 -40
  571. data/app/workflows/spree/returns/purchase_label.rb +0 -32
  572. data/lib/spree/analytics.rb +0 -11
  573. data/lib/spree/core/preferences/scoped_store.rb +0 -34
  574. data/lib/spree/core/preferences/store.rb +0 -105
  575. data/lib/spree/translation_migrations.rb +0 -52
@@ -13,6 +13,7 @@ module Spree
13
13
  include Spree::Stores::Setup
14
14
  include Spree::Stores::Markets
15
15
  include Spree::Stores::Channels
16
+ include Spree::Stores::EmailBranding
16
17
  include Spree::StoreDataSources
17
18
  include Spree::Security::Stores if defined?(Spree::Security::Stores)
18
19
  include Spree::UserManagement
@@ -40,11 +41,16 @@ module Spree
40
41
  #
41
42
  # Preferences
42
43
  #
44
+ UNIT_SYSTEMS = %w[metric imperial].freeze
45
+
43
46
  # general preferences
44
- preference :admin_locale, :string
45
- preference :timezone, :string, default: Time.zone.name
46
- preference :weight_unit, :string, default: 'lb'
47
- preference :unit_system, :string, default: 'imperial'
47
+ preference :admin_locale, :string, format: :locale
48
+ preference :timezone, :string, format: :timezone, default: Time.zone.name
49
+ preference :weight_unit, :string, default: 'lb', choices: -> { Spree::Variant::WEIGHT_UNITS }
50
+ preference :unit_system, :string, default: 'imperial', choices: -> { UNIT_SYSTEMS }
51
+ # Anonymous identifier of this installation, kept on the default store
52
+ # (see Spree.install_id). Written by Spree, never by the operator.
53
+ preference :install_id, :string, internal: true, nullable: true
48
54
  # email preferences
49
55
  preference :send_consumer_transactional_emails, :boolean, default: true
50
56
  # Sellers are a different audience from shoppers, with their own reasons to
@@ -69,7 +75,8 @@ module Spree
69
75
  # Who pays this store's sellers. Blank means core's record-only provider,
70
76
  # so a marketplace that has connected nothing still keeps a correct ledger
71
77
  # and settles by hand.
72
- preference :payout_provider, :string, default: nil
78
+ preference :payout_provider, :string, default: nil,
79
+ parse_on_set: ->(value) { Spree::ApiTyped.class_name_for(Spree.payout_providers, value) }
73
80
  # Refused at write time rather than silently falling back at read time: an
74
81
  # operator who mistypes a provider would otherwise get a bookkeeping-only
75
82
  # ledger and no indication anywhere that their choice was ignored.
@@ -78,22 +85,22 @@ module Spree
78
85
  # How often sellers are settled, unless one carries its own schedule.
79
86
  # Monthly by default because it is the interval that needs least of an
80
87
  # operator paying by hand, which is what the built-in provider expects.
81
- preference :default_payouts_schedule_interval, :string, default: 'monthly'
88
+ preference :default_payouts_schedule_interval, :string, default: 'monthly', choices: -> { Spree::Seller::PAYOUT_INTERVALS }
82
89
  validates :preferred_default_payouts_schedule_interval,
83
90
  inclusion: { in: Spree::Seller::PAYOUT_INTERVALS }, allow_blank: true
84
91
  # What a seller's balance must reach before a settlement is worth sending;
85
92
  # below it the balance carries to the next period. Zero pays whatever is
86
93
  # owed, which is right for a provider that moves money for free.
87
- preference :default_minimum_payout_amount, :decimal, default: 0
94
+ preference :default_minimum_payout_amount, :money, default: 0
88
95
  # Checkout preferences
89
96
  # Store-level fallback for the channel-owned `guest_checkout` preference
90
97
  # (see Spree::Channel::Gating). Retained so existing accessors keep working.
91
98
  preference :guest_checkout, :boolean, default: true
92
99
  # Store-level fallback for the channel-owned `storefront_access` posture.
93
- preference :storefront_access, :string, default: 'public'
100
+ preference :storefront_access, :string, default: 'public', choices: -> { Spree::Channel::Gating::STOREFRONT_ACCESS }
94
101
  # Canonical storefront origin used in customer-facing emails and links,
95
102
  # e.g. "https://myshop.com" — see #storefront_url for the fallback chain.
96
- preference :storefront_url, :string
103
+ preference :storefront_url, :string, format: :url
97
104
  preference :special_instructions_enabled, :boolean, default: false
98
105
  # Advertises a confirm/review step for every checkout, even when no
99
106
  # payment method asks for one. Payment methods that require confirmation
@@ -103,7 +110,8 @@ module Spree
103
110
  # Store-wide default for when a customer is charged rather than only
104
111
  # authorized. A payment method's own capture_method wins when set.
105
112
  # See Spree::CaptureMethod.
106
- preference :capture_method, :string, default: Spree::CaptureMethod::DEFAULT_CAPTURE_METHOD
113
+ preference :capture_method, :string, default: Spree::CaptureMethod::DEFAULT_CAPTURE_METHOD,
114
+ choices: -> { Spree::CaptureMethod::CAPTURE_METHODS }
107
115
  preference :stock_reservations_enabled, :boolean, default: true
108
116
  # Which address a sale's tax is computed against. Stores selling where tax
109
117
  # follows the destination keep this on; billing-address jurisdictions turn
@@ -115,9 +123,9 @@ module Spree
115
123
  preference :inventory_provider, :string, default: 'internal'
116
124
  # What happens when an external source cannot be reached.
117
125
  preference :pricing_provider_failure_policy, :string,
118
- default: Spree::ProviderFailurePolicy::DEFAULT_PRICING_POLICY
126
+ default: Spree::ProviderFailurePolicy::DEFAULT_PRICING_POLICY, choices: -> { Spree::ProviderFailurePolicy::VALUES }
119
127
  preference :inventory_provider_failure_policy, :string,
120
- default: Spree::ProviderFailurePolicy::DEFAULT_INVENTORY_POLICY
128
+ default: Spree::ProviderFailurePolicy::DEFAULT_INVENTORY_POLICY, choices: -> { Spree::ProviderFailurePolicy::VALUES }
121
129
  # Catalog preferences
122
130
  preference :track_inventory_levels, :boolean, default: true
123
131
  # On-hand quantity at or below which a tracked variant counts as running
@@ -151,17 +159,34 @@ module Spree
151
159
  preference :digital_asset_link_expire_time, :integer, default: 300
152
160
  # Class name of the Spree::OrderRouting::Strategy::Base subclass that
153
161
  # decides which StockLocation fulfills which items.
154
- preference :order_routing_strategy, :string, default: 'Spree::OrderRouting::Strategy::Rules'
162
+ preference :order_routing_strategy, :string, default: 'Spree::OrderRouting::Strategy::Rules',
163
+ parse_on_set: ->(value) { Spree::ApiTyped.class_name_for(Spree.order_routing.strategies, value) }
155
164
 
156
165
  # Document numbering (docs/plans/6.0-document-numbers.md). The format
157
166
  # applies to every numbered document; prefix, suffix and starting value
158
167
  # are order-only — other document types keep their code-level prefixes.
159
168
  # Changes affect future numbers only; existing numbers are permanent.
160
- preference :document_number_format, :string, default: 'sequential'
169
+ preference :document_number_format, :string, default: 'sequential', choices: -> { Spree::NumberGenerators::Registry::FORMATS.keys }
161
170
  preference :order_number_prefix, :string, default: 'R'
162
171
  preference :order_number_suffix, :string, default: ''
163
172
  preference :order_number_sequence_start, :integer, default: 1001
164
173
 
174
+ # The settings the API reads and writes under their plain names.
175
+ exposes_preferences :admin_locale, :timezone, :storefront_url, :weight_unit, :unit_system, :storefront_access, :guest_checkout,
176
+ :always_include_confirm_step, :company_field_enabled, :address_requires_company,
177
+ :address_requires_phone, :capture_method, :track_inventory_levels, :stock_reservations_enabled,
178
+ :low_stock_threshold, :tax_using_ship_address, :track_price_history,
179
+ :show_products_without_price, :disable_sku_validation, :order_routing_strategy,
180
+ :pricing_provider, :inventory_provider, :pricing_provider_failure_policy,
181
+ :inventory_provider_failure_policy, :payout_provider, :default_payouts_schedule_interval,
182
+ :default_minimum_payout_amount, :auto_approve_sellers, :auto_approve_seller_products,
183
+ :send_seller_transactional_emails, :default_commission_tax_rate, :document_number_format,
184
+ :order_number_prefix, :order_number_suffix, :order_number_sequence_start,
185
+ :limit_digital_download_count, :digital_asset_authorized_clicks,
186
+ :limit_digital_download_days, :digital_asset_authorized_days,
187
+ :send_consumer_transactional_emails, :email_accent_color, :email_background_color,
188
+ :email_card_color, :email_text_color, :email_heading_color, :email_font
189
+
165
190
  #
166
191
  # Associations
167
192
  #
@@ -300,6 +325,8 @@ module Spree
300
325
  has_many :policies, class_name: 'Spree::Policy', dependent: :destroy, as: :owner
301
326
 
302
327
  has_many :webhook_endpoints, class_name: 'Spree::WebhookEndpoint', dependent: :destroy, inverse_of: :store
328
+ has_many :email_templates, class_name: 'Spree::EmailTemplate', dependent: :destroy, inverse_of: :store
329
+ has_many :email_template_drafts, class_name: 'Spree::EmailTemplateDraft', dependent: :destroy, inverse_of: :store
303
330
  has_many :webhook_deliveries, through: :webhook_endpoints, class_name: 'Spree::WebhookDelivery'
304
331
 
305
332
  has_many :channels, class_name: 'Spree::Channel', dependent: :destroy
@@ -335,6 +362,10 @@ module Spree
335
362
  validates :preferred_default_commission_tax_rate,
336
363
  numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 }
337
364
  validates :preferred_storefront_access, inclusion: { in: Spree::Channel::Gating::STOREFRONT_ACCESS }
365
+ # Blank falls back to the defaults where they are read, so a store saved
366
+ # with one before these checks existed stays savable.
367
+ validates :preferred_unit_system, inclusion: { in: UNIT_SYSTEMS }, allow_blank: true
368
+ validates :preferred_weight_unit, inclusion: { in: Spree::Variant::WEIGHT_UNITS }, allow_blank: true
338
369
  validates :preferred_document_number_format,
339
370
  inclusion: { in: Spree::NumberGenerators::Registry::FORMATS.keys }
340
371
  validates :preferred_order_number_sequence_start,
@@ -362,6 +393,7 @@ module Spree
362
393
  #
363
394
  has_one_attached :logo, service: Spree.public_storage_service_name
364
395
  has_one_attached :mailer_logo, service: Spree.public_storage_service_name
396
+ signed_id_attachments :logo, :mailer_logo
365
397
 
366
398
  # First-run setup credential (docs/plans/6.0-store-context-and-first-run-setup.md):
367
399
  # printed by the installer, only consulted by the setup endpoint while no
@@ -384,6 +416,7 @@ module Spree
384
416
  before_validation :set_default_code, on: :create
385
417
  before_validation :normalize_preferred_storefront_url
386
418
  before_save :ensure_default_exists_and_is_unique
419
+ before_save :set_install_id
387
420
  after_create :create_default_policies
388
421
  after_create :create_default_delivery_profile
389
422
 
@@ -475,14 +508,12 @@ module Spree
475
508
  #
476
509
  # @return [Class]
477
510
  def payout_provider_class
478
- configured = preferred_payout_provider.presence
479
511
  # A name no longer in the registry — a typo, or a gem since removed —
480
512
  # would otherwise raise inside a subscriber on every fulfillment and stop
481
513
  # the ledger recording anything. The built-in provider keeps the books
482
514
  # until an operator fixes the setting.
483
- configured = nil unless Spree.payout_providers.any? { |provider| provider.to_s == configured }
484
-
485
- (configured || Spree.default_payout_provider.to_s).constantize
515
+ Spree::ApiTyped.registered_class(Spree.payout_providers, preferred_payout_provider) ||
516
+ Spree.default_payout_provider.to_s.constantize
486
517
  end
487
518
 
488
519
  def formatted_url
@@ -521,6 +552,7 @@ module Spree
521
552
  end
522
553
 
523
554
  # Returns the storefront origin URL for use in customer-facing emails and links.
555
+ # Replaces the plain `storefront_url` reader `exposes_preferences` defines.
524
556
  # Uses the `storefront_url` preference when set, then the oldest non-loopback
525
557
  # allowed origin (the `http://localhost` origin seeded on install must never
526
558
  # leak into customer emails), otherwise falls back to formatted_url.
@@ -543,6 +575,21 @@ module Spree
543
575
  allowed_origins.any? { |allowed_origin| allowed_origin.matches?(url) }
544
576
  end
545
577
 
578
+ # The logo emails show: the dedicated mailer logo, else the store logo.
579
+ #
580
+ # @return [ActiveStorage::Attached::One, nil] nil when neither is an image
581
+ def email_logo
582
+ logo = mailer_logo.attached? ? mailer_logo : self.logo
583
+ logo if logo.attached? && logo.variable?
584
+ end
585
+
586
+ # The address customers are told to write to: the support address, else the sender address.
587
+ #
588
+ # @return [String, nil]
589
+ def support_email_address
590
+ customer_support_email.presence || mail_from_address
591
+ end
592
+
546
593
  # Returns the states available for checkout for the store
547
594
  # @param country [Spree::Country] the country to get the states for
548
595
  # @return [Array<Spree::State>]
@@ -613,7 +660,7 @@ module Spree
613
660
  @default_stock_location ||= begin
614
661
  stock_location_scope = stock_locations.first_party.where(default: true)
615
662
  stock_location_scope.first || ActiveRecord::Base.connected_to(role: :writing) do
616
- stock_location_scope.create(default: true, name: Spree.t(:default_stock_location_name),
663
+ stock_location_scope.create(default: true, name: I18n.t('spree.default_stock_location_name'),
617
664
  country_code: default_country&.iso)
618
665
  end
619
666
  end
@@ -699,6 +746,10 @@ module Spree
699
746
  I18n.t(key, locale: locale, default: I18n.t(key, locale: :en))
700
747
  end
701
748
 
749
+ def set_install_id
750
+ self.preferred_install_id = SecureRandom.uuid if preferred_install_id.blank?
751
+ end
752
+
702
753
  def ensure_default_exists_and_is_unique
703
754
  if default
704
755
  Spree::Store.where.not(id: id).update_all(default: false)
@@ -5,6 +5,9 @@ module Spree
5
5
  include Spree::SingleStoreResource
6
6
  include Spree::HasCustomFields
7
7
  include Spree::Metadata
8
+ include Spree::CanonicalDecimals
9
+
10
+ canonical_decimals :amount
8
11
 
9
12
  publishes_lifecycle_events
10
13
 
@@ -18,7 +21,6 @@ module Spree
18
21
  AUTHORIZE_ACTION = 'authorize'.freeze
19
22
  ALLOCATION_ACTION = 'allocation'.freeze
20
23
 
21
- belongs_to :store, class_name: 'Spree::Store'
22
24
  # A gift card applied to a guest cart issues store credit with no customer
23
25
  # to attach it to.
24
26
  belongs_to :customer, class_name: "::#{Spree.customer_class}", optional: true
@@ -106,13 +108,11 @@ module Spree
106
108
  extend Spree::DisplayMoney
107
109
  money_methods :amount, :amount_used, :amount_remaining, :amount_authorized
108
110
 
109
- def amount=(amount)
110
- self[:amount] = Spree::LocalizedNumber.parse(amount)
111
- end
112
-
113
111
  self.whitelisted_ransackable_attributes = %w[customer_id created_by_id amount currency memo]
112
+ search_by :memo
114
113
  self.whitelisted_ransackable_associations = %w[customer created_by]
115
114
  self.whitelisted_ransackable_scopes = %w[outstanding from_gift_card]
115
+ self.ransackable_scope_types = %w[outstanding from_gift_card].index_with('boolean')
116
116
  # Staff notes and who issued the credit are back-office data.
117
117
  self.private_ransackable_attributes = { store: %w[memo created_by_id] }
118
118
 
@@ -146,16 +146,16 @@ module Spree
146
146
  )
147
147
  authorization_code
148
148
  else
149
- errors.add(:base, :insufficient_authorized_amount, message: Spree.t('store_credit_payment_method.insufficient_authorized_amount'))
149
+ errors.add(:base, :insufficient_authorized_amount, message: I18n.t('spree.store_credit_payment_method.insufficient_authorized_amount'))
150
150
  false
151
151
  end
152
152
  end
153
153
 
154
154
  def validate_authorization(amount, order_currency)
155
155
  if BigDecimal(amount_remaining, 3) < BigDecimal(amount, 3)
156
- errors.add(:base, :insufficient_funds, message: Spree.t('store_credit_payment_method.insufficient_funds'))
156
+ errors.add(:base, :insufficient_funds, message: I18n.t('spree.store_credit_payment_method.insufficient_funds'))
157
157
  elsif currency != order_currency
158
- errors.add(:base, :currency_mismatch, message: Spree.t('store_credit_payment_method.currency_mismatch'))
158
+ errors.add(:base, :currency_mismatch, message: I18n.t('spree.store_credit_payment_method.currency_mismatch'))
159
159
  end
160
160
  errors.blank?
161
161
  end
@@ -165,7 +165,7 @@ module Spree
165
165
 
166
166
  if amount <= amount_authorized
167
167
  if currency != order_currency
168
- errors.add(:base, :currency_mismatch, message: Spree.t('store_credit_payment_method.currency_mismatch'))
168
+ errors.add(:base, :currency_mismatch, message: I18n.t('spree.store_credit_payment_method.currency_mismatch'))
169
169
  false
170
170
  else
171
171
  update!(
@@ -179,7 +179,7 @@ module Spree
179
179
  authorization_code
180
180
  end
181
181
  else
182
- errors.add(:base, :insufficient_authorized_amount, message: Spree.t('store_credit_payment_method.insufficient_authorized_amount'))
182
+ errors.add(:base, :insufficient_authorized_amount, message: I18n.t('spree.store_credit_payment_method.insufficient_authorized_amount'))
183
183
  false
184
184
  end
185
185
  end
@@ -196,7 +196,7 @@ module Spree
196
196
  true
197
197
  else
198
198
  errors.add(:base, :unable_to_void, auth_code: authorization_code,
199
- message: Spree.t('store_credit_payment_method.unable_to_void', auth_code: authorization_code))
199
+ message: I18n.t('spree.store_credit_payment_method.unable_to_void', auth_code: authorization_code))
200
200
  false
201
201
  end
202
202
  end
@@ -206,7 +206,7 @@ module Spree
206
206
  capture_event = store_credit_events.find_by(action: CAPTURE_ACTION, authorization_code: authorization_code)
207
207
 
208
208
  if currency != order_currency # sanity check to make sure the order currency hasn't changed since the auth
209
- errors.add(:base, :currency_mismatch, message: Spree.t('store_credit_payment_method.currency_mismatch'))
209
+ errors.add(:base, :currency_mismatch, message: I18n.t('spree.store_credit_payment_method.currency_mismatch'))
210
210
  false
211
211
  elsif capture_event && amount <= capture_event.amount
212
212
  action_attributes = {
@@ -219,7 +219,7 @@ module Spree
219
219
  true
220
220
  else
221
221
  errors.add(:base, :unable_to_credit, auth_code: authorization_code,
222
- message: Spree.t('store_credit_payment_method.unable_to_credit', auth_code: authorization_code))
222
+ message: I18n.t('spree.store_credit_payment_method.unable_to_credit', auth_code: authorization_code))
223
223
  false
224
224
  end
225
225
  end
@@ -24,15 +24,15 @@ module Spree
24
24
  def display_action
25
25
  case action
26
26
  when Spree::StoreCredit::CAPTURE_ACTION
27
- Spree.t('store_credit.captured')
27
+ I18n.t('spree.store_credit.captured')
28
28
  when Spree::StoreCredit::AUTHORIZE_ACTION
29
- Spree.t('store_credit.authorized')
29
+ I18n.t('spree.store_credit.authorized')
30
30
  when Spree::StoreCredit::ALLOCATION_ACTION
31
- Spree.t('store_credit.allocated')
31
+ I18n.t('spree.store_credit.allocated')
32
32
  when Spree::StoreCredit::ELIGIBLE_ACTION
33
- Spree.t('store_credit.eligible')
33
+ I18n.t('spree.store_credit.eligible')
34
34
  when Spree::StoreCredit::VOID_ACTION, Spree::StoreCredit::CREDIT_ACTION
35
- Spree.t('store_credit.credit')
35
+ I18n.t('spree.store_credit.credit')
36
36
  end
37
37
  end
38
38
 
@@ -32,6 +32,7 @@ module Spree
32
32
  normalizes :name, :contact_name, :phone, with: ->(value) { value.strip }
33
33
 
34
34
  self.whitelisted_ransackable_attributes = %w[name contact_name email phone city country_code created_at]
35
+ search_by :name, :contact_name, :email
35
36
 
36
37
  # The postal address, built from this row's own columns the way
37
38
  # {Spree::StockLocation#address} does. Unsaved, and blank when nothing has
@@ -16,6 +16,7 @@ module Spree
16
16
  before_save :set_default_category
17
17
 
18
18
  self.whitelisted_ransackable_attributes = %w[name is_default tax_code]
19
+ search_by :name
19
20
 
20
21
  # The category applied to taxable records that carry none of their own.
21
22
  #
@@ -9,6 +9,8 @@ module Spree
9
9
  # valid in one state and not the next is the ordinary case, and the country
10
10
  # and state columns say exactly where it holds.
11
11
  class TaxExemptionCertificate < Spree.base_class
12
+ publishes_event :verified
13
+
12
14
  has_prefix_id :cert
13
15
 
14
16
  include Spree::HasStatus
@@ -25,6 +27,7 @@ module Spree
25
27
  # Confidential, so the private service rather than the public one that
26
28
  # serves product images.
27
29
  has_one_attached :document, service: Spree.private_storage_service_name
30
+ signed_id_attachments :document
28
31
 
29
32
  validates :certificate_number, :reason_code, presence: true
30
33
  # Certificates exist only on legal-entity nodes — a division's purchases
@@ -36,6 +36,8 @@ module Spree
36
36
  # directly. It is a habit of the gems that use it, not a rule this model
37
37
  # applies.
38
38
  class TaxIdentifier < Spree.base_class
39
+ publishes_event :number_changed
40
+
39
41
  has_prefix_id :txi
40
42
 
41
43
  # Statuses the platform records rather than the buyer chooses: nil means
@@ -150,7 +152,7 @@ module Spree
150
152
  # The kind as the dashboard shows it, falling back to the raw key so an
151
153
  # extension's kind reads as itself rather than blank.
152
154
  def kind_label
153
- Spree.t("tax_identifier_kinds.#{kind}", default: kind.to_s.humanize)
155
+ I18n.t("spree.tax_identifier_kinds.#{kind}", default: kind.to_s.humanize)
154
156
  end
155
157
 
156
158
  # The class registered for this kind, or nil when nothing is registered and
@@ -4,6 +4,11 @@ module Spree
4
4
  # per estimate. Snapshot columns (+rate+, +label+, +provider_id+) keep rows
5
5
  # self-describing after a TaxRate is deleted or when an external provider
6
6
  # computed them.
7
+ #
8
+ # Rows on a return, claim or exchange line are post-sale: the tax given back
9
+ # (+credit+), or the tax on an exchange's replacement. They are owned by the
10
+ # order like every other row but never count towards its totals — the order
11
+ # reads only {.sale} rows.
7
12
  class TaxLine < Spree.base_class
8
13
  include Spree::TypedAdjustmentLine
9
14
 
@@ -35,6 +40,13 @@ module Spree
35
40
  belongs_to :line_item, class_name: 'Spree::LineItem', optional: true
36
41
  belongs_to :fulfillment, class_name: 'Spree::Fulfillment', optional: true
37
42
  belongs_to :fee, class_name: 'Spree::Fee', optional: true
43
+ belongs_to :return_line_item, class_name: 'Spree::ReturnLineItem', optional: true
44
+ belongs_to :claim_line_item, class_name: 'Spree::ClaimLineItem', optional: true
45
+ belongs_to :exchange_line_item, class_name: 'Spree::ExchangeLineItem', optional: true
46
+
47
+ # The sale row a credit gives back — what caps repeated credits against one
48
+ # line, and the original a credit note refers to.
49
+ belongs_to :original_tax_line, class_name: 'Spree::TaxLine', optional: true
38
50
 
39
51
  # Tax included in price vs additional. Per-row (mixed regimes on one order).
40
52
  attribute :included, :boolean, default: false
@@ -46,20 +58,50 @@ module Spree
46
58
  inclusion: { in: ->(tax_line) { tax_line.class.taxability_reasons } },
47
59
  allow_nil: true
48
60
  validate :exactly_one_adjustable
61
+ validate :post_sale_owned_by_order
49
62
 
50
63
  # Tax reporting is the reason the treatment columns exist — "which country's
51
64
  # tax was this, and which sales were reverse-charged" has to be answerable.
52
65
  self.whitelisted_ransackable_attributes = %w[taxability_reason country_code state_code included provider_id]
53
66
 
67
+ POST_SALE_KEYS = %i[return_line_item_id claim_line_item_id exchange_line_item_id].freeze
68
+
69
+ ADJUSTABLE_KEYS = {
70
+ 'Spree::LineItem' => :line_item_id,
71
+ 'Spree::Fulfillment' => :fulfillment_id,
72
+ 'Spree::Fee' => :fee_id,
73
+ 'Spree::ReturnLineItem' => :return_line_item_id,
74
+ 'Spree::ClaimLineItem' => :claim_line_item_id,
75
+ 'Spree::ExchangeLineItem' => :exchange_line_item_id
76
+ }.freeze
77
+
54
78
  scope :included_in_price, -> { where(included: true) }
55
79
  scope :additional, -> { where(included: false) }
56
80
  scope :for_line_items, -> { where.not(line_item_id: nil) }
57
81
  scope :for_fulfillments, -> { where.not(fulfillment_id: nil) }
58
82
  scope :for_fees, -> { where.not(fee_id: nil) }
83
+ scope :sale, -> { where(POST_SALE_KEYS.index_with(nil)) }
84
+ scope :post_sale, -> { where.not(POST_SALE_KEYS.index_with(nil)) }
85
+ scope :credits, -> { where(credit: true) }
86
+ scope :charges, -> { where(credit: false) }
87
+
88
+ # The foreign key a row uses to point at an item of this class.
89
+ #
90
+ # @param klass [Class]
91
+ # @return [Symbol]
92
+ # @raise [ArgumentError] for a class that is not taxed
93
+ def self.adjustable_key_for(klass)
94
+ ADJUSTABLE_KEYS.fetch(klass.name) { raise ArgumentError, "#{klass} is not taxable" }
95
+ end
59
96
 
60
- # @return [Spree::LineItem, Spree::Fulfillment, Spree::Fee, nil]
97
+ # @return [Spree::LineItem, Spree::Fulfillment, Spree::Fee, Spree::ReturnLineItem,
98
+ # Spree::ClaimLineItem, Spree::ExchangeLineItem, nil]
61
99
  def adjustable
62
- line_item || fulfillment || fee
100
+ line_item || fulfillment || fee || return_line_item || claim_line_item || exchange_line_item
101
+ end
102
+
103
+ def post_sale?
104
+ POST_SALE_KEYS.any? { |key| self[key].present? }
63
105
  end
64
106
 
65
107
  def included?
@@ -73,7 +115,15 @@ module Spree
73
115
  private
74
116
 
75
117
  def exactly_one_adjustable
76
- errors.add(:base, :exactly_one_adjustable, message: Spree.t('errors.messages.exactly_one_adjustable')) unless [line_item, fulfillment, fee].compact.one?
118
+ adjustables = [line_item, fulfillment, fee, return_line_item, claim_line_item, exchange_line_item]
119
+ errors.add(:base, :exactly_one_adjustable, message: I18n.t('spree.errors.messages.exactly_one_adjustable')) unless adjustables.compact.one?
120
+ end
121
+
122
+ # Returns, claims and exchanges only exist on placed orders.
123
+ def post_sale_owned_by_order
124
+ return unless post_sale? && order.nil?
125
+
126
+ errors.add(:base, :exactly_one_of_cart_or_order, message: I18n.t('spree.errors.messages.exactly_one_of_cart_or_order'))
77
127
  end
78
128
  end
79
129
  end
@@ -3,12 +3,16 @@ module Spree
3
3
  # Contract for tax providers — the only sanctioned writers of
4
4
  # {Spree::TaxLine} rows. +estimate+ must use replace-all set semantics per
5
5
  # target item (delete the item's stale lines, insert fresh ones); that is
6
- # what keeps tax correct after address or item changes. Commit/void/refund
7
- # are lifecycle no-ops for providers without a remote ledger.
6
+ # what keeps tax correct after address or item changes, and the post-sale
7
+ # +estimate_refund+ / +estimate_replacement+ follow the same rule.
8
+ # Commit/void/refund/commit_replacement are lifecycle no-ops for providers
9
+ # without a remote ledger.
8
10
  #
9
11
  # Providers are stateless and constructed without arguments, so anything
10
12
  # request-specific arrives as an argument rather than through the instance.
11
13
  class Base
14
+ extend Spree::ApiTyped
15
+
12
16
  # Domains this provider cannot handle, so a merchant is warned when
13
17
  # pairing it with a market instead of silently under-collecting. Declared
14
18
  # on the class because core reads it while presenting the choice, before
@@ -47,8 +51,8 @@ module Spree
47
51
  unsupported_capabilities.map do |capability|
48
52
  {
49
53
  key: capability.to_s,
50
- label: Spree.t("tax_capabilities.#{capability}.label", default: capability.to_s.humanize),
51
- description: Spree.t("tax_capabilities.#{capability}.description", default: nil)
54
+ label: I18n.t("spree.tax_capabilities.#{capability}.label", default: capability.to_s.humanize),
55
+ description: I18n.t("spree.tax_capabilities.#{capability}.description", default: nil)
52
56
  }.compact
53
57
  end
54
58
  end
@@ -61,7 +65,7 @@ module Spree
61
65
  # @return [Hash]
62
66
  def self.to_api_hash(store)
63
67
  {
64
- id: name,
68
+ id: api_type,
65
69
  name: display_name,
66
70
  available: available_for_store?(store),
67
71
  unsupported_capabilities: unsupported_capability_details,
@@ -128,19 +132,72 @@ module Spree
128
132
  nil
129
133
  end
130
134
 
135
+ # Works out the tax given back on lines of a return, claim or exchange,
136
+ # and writes it as credit TaxLine rows on them. The customer is refunded
137
+ # exactly what these rows hold, so this — not +refund+ — decides the
138
+ # figure.
139
+ #
140
+ # Each item credits its +credited_quantity+, and zero means no rows.
141
+ # Replace-all per item, as +estimate+: the rows are rewritten when the
142
+ # warehouse counts what arrived and again when the money goes back.
143
+ #
144
+ # A provider may quote the credit, for example at the original
145
+ # +tax_date+, or give back the recorded share of what the sale charged —
146
+ # {Spree::TaxProvider::RecordedShare}, which Internal uses. Either way
147
+ # it answers in the same rows.
148
+ #
149
+ # @param order [Spree::Order] a placed order
150
+ # @param items [Array<Spree::ReturnLineItem, Spree::ClaimLineItem, Spree::ExchangeLineItem>]
151
+ # @param amounts [Hash{Object => BigDecimal}, nil] the money refunded per
152
+ # item when it is less than the item's worth — a restocking fee, a
153
+ # part refund. Tax is then credited in the same proportion. Nil
154
+ # credits every item's full worth.
155
+ # @param tax_date [Time, nil] the date whose rates apply; nil = order.completed_at
156
+ # @return [void]
157
+ # @raise [Spree::Tax::ProviderError] when the credit could not be worked out
158
+ def estimate_refund(order, items, amounts: nil, tax_date: nil)
159
+ raise NotImplementedError, "Please implement 'estimate_refund' in your tax provider: #{self.class.name}"
160
+ end
161
+
162
+ # Taxes the replacement an exchange sends out, as a new sale, and writes
163
+ # it as charge TaxLine rows on the exchange lines. Never touches the
164
+ # order's own rows, which stay as the sale was placed. Replace-all per
165
+ # item; each item is taxed on its +taxable_basis+ under its
166
+ # +tax_category_id+, and one whose +credited_quantity+ is zero ships
167
+ # nothing and ends with no rows.
168
+ #
169
+ # @param order [Spree::Order] a placed order
170
+ # @param items [Array<Spree::ExchangeLineItem>]
171
+ # @param tax_date [Time, nil] date whose rates apply; nil = now
172
+ # @param tax_identifier [Spree::TaxIdentifier, nil] the order's frozen registration
173
+ # @param exemptions [Array] exemption evidence to apply
174
+ # @return [void]
175
+ # @raise [Spree::Tax::ProviderError] when the tax could not be worked out
176
+ def estimate_replacement(order, items, tax_date: nil, tax_identifier: nil, exemptions: [])
177
+ raise NotImplementedError, "Please implement 'estimate_replacement' in your tax provider: #{self.class.name}"
178
+ end
179
+
180
+ # Files an exchange's replacement as a sale. Called once the exchange is
181
+ # fulfilled; must be idempotent, keyed on the exchange. No-op for a
182
+ # provider without a remote ledger.
183
+ #
184
+ # @param order [Spree::Order]
185
+ # @param items [Array<Spree::ExchangeLineItem>]
186
+ # @return [void]
187
+ def commit_replacement(order, items); end
188
+
131
189
  # Reports a partial credit against the committed document, keyed to the
132
- # original transaction rather than voiding and re-committing it.
190
+ # original transaction rather than voiding and re-committing it. Called
191
+ # after the money has moved.
133
192
  #
134
- # +amount+ is what the customer was actually refunded, which is not always
135
- # the returned lines' worth: an admin may keep a restocking fee or refund
136
- # a goodwill figure of their own. A provider must credit no more tax than
137
- # that refund carries — crediting every returned line when only part of
138
- # their value went back would reclaim tax the merchant never repaid, and a
139
- # return is marked refunded once, so nothing later corrects it. Where the
140
- # amount is short, allocate proportionally.
193
+ # By then each item's credit rows hold what went back (see
194
+ # +estimate_refund+), and a provider must credit no more than they do:
195
+ # the customer was repaid that tax and no more. +amount+ is the money
196
+ # refunded, which may be less than the items are worth when an admin kept
197
+ # a restocking fee or refunded a goodwill figure of their own.
141
198
  #
142
199
  # @param order [Spree::Order]
143
- # @param return_items [Array<Spree::ReturnLineItem>] the returned lines
200
+ # @param return_items [Array<Spree::ReturnLineItem, Spree::ClaimLineItem, Spree::ExchangeLineItem>]
144
201
  # @param amount [BigDecimal, nil] the refund issued; nil = the lines' full worth
145
202
  # @param tax_date [Time, nil] the original supply date; nil = order.completed_at
146
203
  # @return [void]