spree_core 5.1.7 → 5.2.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 (400) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/payment_icons/ach.svg +1 -0
  3. data/app/assets/images/payment_icons/achdirectdebit.svg +1 -0
  4. data/app/assets/images/payment_icons/ada.svg +1 -0
  5. data/app/assets/images/payment_icons/adyen.svg +1 -0
  6. data/app/assets/images/payment_icons/affinbank.svg +1 -0
  7. data/app/assets/images/payment_icons/affirm.svg +1 -0
  8. data/app/assets/images/payment_icons/afterpay.svg +1 -0
  9. data/app/assets/images/payment_icons/airtel_money.svg +1 -0
  10. data/app/assets/images/payment_icons/airteltigo_mobile_money.svg +1 -0
  11. data/app/assets/images/payment_icons/alandsbanken.svg +1 -0
  12. data/app/assets/images/payment_icons/alipay.svg +1 -0
  13. data/app/assets/images/payment_icons/alipay_hk.svg +1 -0
  14. data/app/assets/images/payment_icons/alliancebank.svg +1 -0
  15. data/app/assets/images/payment_icons/alma.svg +1 -0
  16. data/app/assets/images/payment_icons/amazon.svg +1 -0
  17. data/app/assets/images/payment_icons/ambank.svg +1 -0
  18. data/app/assets/images/payment_icons/american_express.svg +1 -0
  19. data/app/assets/images/payment_icons/apecoin.svg +1 -0
  20. data/app/assets/images/payment_icons/apple_pay.svg +1 -0
  21. data/app/assets/images/payment_icons/arbitrum.svg +1 -0
  22. data/app/assets/images/payment_icons/atome.svg +1 -0
  23. data/app/assets/images/payment_icons/authorizenet.svg +1 -0
  24. data/app/assets/images/payment_icons/avalanche.svg +1 -0
  25. data/app/assets/images/payment_icons/bacs.svg +1 -0
  26. data/app/assets/images/payment_icons/bancontact.svg +1 -0
  27. data/app/assets/images/payment_icons/bangkokbank.svg +1 -0
  28. data/app/assets/images/payment_icons/bankislam.svg +1 -0
  29. data/app/assets/images/payment_icons/bankmuamalat.svg +1 -0
  30. data/app/assets/images/payment_icons/bankofamerica.svg +1 -0
  31. data/app/assets/images/payment_icons/bankrakyat.svg +1 -0
  32. data/app/assets/images/payment_icons/base.svg +1 -0
  33. data/app/assets/images/payment_icons/becs.svg +1 -0
  34. data/app/assets/images/payment_icons/benefit.svg +1 -0
  35. data/app/assets/images/payment_icons/billie.svg +1 -0
  36. data/app/assets/images/payment_icons/bitcoin.svg +1 -0
  37. data/app/assets/images/payment_icons/bitcoin_cash.svg +1 -0
  38. data/app/assets/images/payment_icons/bizum.svg +1 -0
  39. data/app/assets/images/payment_icons/blik.svg +1 -0
  40. data/app/assets/images/payment_icons/bnbchain.svg +1 -0
  41. data/app/assets/images/payment_icons/bogus.svg +1 -0
  42. data/app/assets/images/payment_icons/bogus_app_coin.svg +1 -0
  43. data/app/assets/images/payment_icons/boleto.svg +1 -0
  44. data/app/assets/images/payment_icons/boost.svg +1 -0
  45. data/app/assets/images/payment_icons/braintree.svg +1 -0
  46. data/app/assets/images/payment_icons/buckaroopaybybank.svg +1 -0
  47. data/app/assets/images/payment_icons/busd.svg +1 -0
  48. data/app/assets/images/payment_icons/cartes_bancaires.svg +1 -0
  49. data/app/assets/images/payment_icons/cash.svg +1 -0
  50. data/app/assets/images/payment_icons/cashappafterpay.svg +1 -0
  51. data/app/assets/images/payment_icons/cashapppay.svg +1 -0
  52. data/app/assets/images/payment_icons/checkout_finance.svg +1 -0
  53. data/app/assets/images/payment_icons/chinabank.svg +1 -0
  54. data/app/assets/images/payment_icons/clearpay.svg +1 -0
  55. data/app/assets/images/payment_icons/collector_bank.svg +1 -0
  56. data/app/assets/images/payment_icons/dai.svg +1 -0
  57. data/app/assets/images/payment_icons/dana.svg +1 -0
  58. data/app/assets/images/payment_icons/dankort.svg +1 -0
  59. data/app/assets/images/payment_icons/danske_bank.svg +1 -0
  60. data/app/assets/images/payment_icons/deutschebank.svg +1 -0
  61. data/app/assets/images/payment_icons/diners_club.svg +1 -0
  62. data/app/assets/images/payment_icons/directbanktransferlatinamerica.svg +1 -0
  63. data/app/assets/images/payment_icons/discover.svg +1 -0
  64. data/app/assets/images/payment_icons/dogecoin.svg +1 -0
  65. data/app/assets/images/payment_icons/duitnow.svg +1 -0
  66. data/app/assets/images/payment_icons/eft_secure.svg +1 -0
  67. data/app/assets/images/payment_icons/eftpos_au.svg +1 -0
  68. data/app/assets/images/payment_icons/eftposau.svg +1 -0
  69. data/app/assets/images/payment_icons/elo.svg +1 -0
  70. data/app/assets/images/payment_icons/eos.svg +1 -0
  71. data/app/assets/images/payment_icons/eps.svg +1 -0
  72. data/app/assets/images/payment_icons/ethereum.svg +1 -0
  73. data/app/assets/images/payment_icons/eurobonuscheckout.svg +1 -0
  74. data/app/assets/images/payment_icons/ezcash.svg +1 -0
  75. data/app/assets/images/payment_icons/fantom.svg +1 -0
  76. data/app/assets/images/payment_icons/fpx.svg +1 -0
  77. data/app/assets/images/payment_icons/gcash.svg +1 -0
  78. data/app/assets/images/payment_icons/generic.svg +1 -0
  79. data/app/assets/images/payment_icons/genericbank.svg +1 -0
  80. data/app/assets/images/payment_icons/gift-card.svg +1 -0
  81. data/app/assets/images/payment_icons/giropay.svg +1 -0
  82. data/app/assets/images/payment_icons/glbepaypal.svg +1 -0
  83. data/app/assets/images/payment_icons/gmobanktransfer.svg +1 -0
  84. data/app/assets/images/payment_icons/gnosis.svg +1 -0
  85. data/app/assets/images/payment_icons/google_pay.svg +1 -0
  86. data/app/assets/images/payment_icons/google_wallet.svg +1 -0
  87. data/app/assets/images/payment_icons/gopay.svg +1 -0
  88. data/app/assets/images/payment_icons/grabpay.svg +1 -0
  89. data/app/assets/images/payment_icons/gusd.svg +1 -0
  90. data/app/assets/images/payment_icons/handelsbanken.svg +1 -0
  91. data/app/assets/images/payment_icons/hongleongbank.svg +1 -0
  92. data/app/assets/images/payment_icons/hypercard.svg +1 -0
  93. data/app/assets/images/payment_icons/hypercash.svg +1 -0
  94. data/app/assets/images/payment_icons/ideal.svg +1 -0
  95. data/app/assets/images/payment_icons/in3viaideal.svg +1 -0
  96. data/app/assets/images/payment_icons/inbank.svg +1 -0
  97. data/app/assets/images/payment_icons/jcb.svg +1 -0
  98. data/app/assets/images/payment_icons/kakao_pay.svg +1 -0
  99. data/app/assets/images/payment_icons/kasikornbank.svg +1 -0
  100. data/app/assets/images/payment_icons/klarna-pay-later.svg +1 -0
  101. data/app/assets/images/payment_icons/klarna-pay-now.svg +1 -0
  102. data/app/assets/images/payment_icons/klarna-slice-it.svg +1 -0
  103. data/app/assets/images/payment_icons/klarna.svg +1 -0
  104. data/app/assets/images/payment_icons/knet.svg +1 -0
  105. data/app/assets/images/payment_icons/krungthaibank.svg +1 -0
  106. data/app/assets/images/payment_icons/landbank.svg +1 -0
  107. data/app/assets/images/payment_icons/laybuybyklarna.svg +1 -0
  108. data/app/assets/images/payment_icons/litecoin.svg +1 -0
  109. data/app/assets/images/payment_icons/lunchcheck.svg +1 -0
  110. data/app/assets/images/payment_icons/mach.svg +1 -0
  111. data/app/assets/images/payment_icons/mada.svg +1 -0
  112. data/app/assets/images/payment_icons/maestro.svg +1 -0
  113. data/app/assets/images/payment_icons/master.svg +1 -0
  114. data/app/assets/images/payment_icons/mayabank.svg +1 -0
  115. data/app/assets/images/payment_icons/maybank.svg +1 -0
  116. data/app/assets/images/payment_icons/maybankm2u.svg +1 -0
  117. data/app/assets/images/payment_icons/maybankqrpay.svg +1 -0
  118. data/app/assets/images/payment_icons/mbway.svg +1 -0
  119. data/app/assets/images/payment_icons/mcash.svg +1 -0
  120. data/app/assets/images/payment_icons/medicinosbankas.svg +1 -0
  121. data/app/assets/images/payment_icons/mercadopago.svg +1 -0
  122. data/app/assets/images/payment_icons/metrobank.svg +1 -0
  123. data/app/assets/images/payment_icons/mobilepay.svg +1 -0
  124. data/app/assets/images/payment_icons/momopay.svg +1 -0
  125. data/app/assets/images/payment_icons/monero.svg +1 -0
  126. data/app/assets/images/payment_icons/mtn_mobile_money.svg +1 -0
  127. data/app/assets/images/payment_icons/mybank.svg +1 -0
  128. data/app/assets/images/payment_icons/naver_pay.svg +1 -0
  129. data/app/assets/images/payment_icons/nelo.svg +1 -0
  130. data/app/assets/images/payment_icons/netbanking.svg +1 -0
  131. data/app/assets/images/payment_icons/novalnetdirectdebitach.svg +1 -0
  132. data/app/assets/images/payment_icons/nubank.svg +1 -0
  133. data/app/assets/images/payment_icons/ocbcbank.svg +1 -0
  134. data/app/assets/images/payment_icons/offlinebanktransferlatinamerica.svg +1 -0
  135. data/app/assets/images/payment_icons/ola_money.svg +1 -0
  136. data/app/assets/images/payment_icons/oney.svg +1 -0
  137. data/app/assets/images/payment_icons/onlinebanking.svg +1 -0
  138. data/app/assets/images/payment_icons/onlinebanktransfer.svg +1 -0
  139. data/app/assets/images/payment_icons/orangemobilemoney.svg +1 -0
  140. data/app/assets/images/payment_icons/otpbank.svg +1 -0
  141. data/app/assets/images/payment_icons/oxxo.svg +1 -0
  142. data/app/assets/images/payment_icons/paybybank.svg +1 -0
  143. data/app/assets/images/payment_icons/paybybankmollie.svg +1 -0
  144. data/app/assets/images/payment_icons/paybybankus.svg +1 -0
  145. data/app/assets/images/payment_icons/paycash.svg +1 -0
  146. data/app/assets/images/payment_icons/payco.svg +1 -0
  147. data/app/assets/images/payment_icons/payeverpaybybank.svg +1 -0
  148. data/app/assets/images/payment_icons/payme.svg +1 -0
  149. data/app/assets/images/payment_icons/paynow.svg +1 -0
  150. data/app/assets/images/payment_icons/paynowmbank.svg +1 -0
  151. data/app/assets/images/payment_icons/paypal.svg +1 -0
  152. data/app/assets/images/payment_icons/paypo.svg +1 -0
  153. data/app/assets/images/payment_icons/payrexxbanktransfer.svg +1 -0
  154. data/app/assets/images/payment_icons/payrexxpaybybank.svg +1 -0
  155. data/app/assets/images/payment_icons/paysafecash.svg +1 -0
  156. data/app/assets/images/payment_icons/pix.svg +1 -0
  157. data/app/assets/images/payment_icons/polygon.svg +1 -0
  158. data/app/assets/images/payment_icons/przelewy24.svg +1 -0
  159. data/app/assets/images/payment_icons/publicbank.svg +1 -0
  160. data/app/assets/images/payment_icons/publicbank_pbe.svg +1 -0
  161. data/app/assets/images/payment_icons/qr_promptpay.svg +1 -0
  162. data/app/assets/images/payment_icons/rabobank.svg +1 -0
  163. data/app/assets/images/payment_icons/revolut.svg +1 -0
  164. data/app/assets/images/payment_icons/rhbbank.svg +1 -0
  165. data/app/assets/images/payment_icons/riverty.svg +1 -0
  166. data/app/assets/images/payment_icons/safetypaybanktransfer.svg +1 -0
  167. data/app/assets/images/payment_icons/samsung_pay.svg +1 -0
  168. data/app/assets/images/payment_icons/satispay.svg +1 -0
  169. data/app/assets/images/payment_icons/scalapay.svg +1 -0
  170. data/app/assets/images/payment_icons/scotiabank.svg +1 -0
  171. data/app/assets/images/payment_icons/seabankid.svg +1 -0
  172. data/app/assets/images/payment_icons/seabankph.svg +1 -0
  173. data/app/assets/images/payment_icons/sepa_bank_transfer.svg +1 -0
  174. data/app/assets/images/payment_icons/sepadirectdebit.svg +1 -0
  175. data/app/assets/images/payment_icons/seveneleven.svg +1 -0
  176. data/app/assets/images/payment_icons/shib.svg +1 -0
  177. data/app/assets/images/payment_icons/shopcash.svg +1 -0
  178. data/app/assets/images/payment_icons/siauliubankas.svg +1 -0
  179. data/app/assets/images/payment_icons/skeps.svg +1 -0
  180. data/app/assets/images/payment_icons/snap_checkout.svg +1 -0
  181. data/app/assets/images/payment_icons/sofort.svg +1 -0
  182. data/app/assets/images/payment_icons/softbank.svg +1 -0
  183. data/app/assets/images/payment_icons/spei.svg +1 -0
  184. data/app/assets/images/payment_icons/storecredit.svg +1 -0
  185. data/app/assets/images/payment_icons/stripe.svg +1 -0
  186. data/app/assets/images/payment_icons/sveacheckout.svg +1 -0
  187. data/app/assets/images/payment_icons/swedbank.svg +1 -0
  188. data/app/assets/images/payment_icons/swish.svg +1 -0
  189. data/app/assets/images/payment_icons/tbibank.svg +1 -0
  190. data/app/assets/images/payment_icons/thanachartbank.svg +1 -0
  191. data/app/assets/images/payment_icons/tnmmoney.svg +1 -0
  192. data/app/assets/images/payment_icons/touchngo.svg +1 -0
  193. data/app/assets/images/payment_icons/trustly.svg +1 -0
  194. data/app/assets/images/payment_icons/twint.svg +1 -0
  195. data/app/assets/images/payment_icons/uaevisa.svg +1 -0
  196. data/app/assets/images/payment_icons/unionpay.svg +1 -0
  197. data/app/assets/images/payment_icons/unzerbanktransfer.svg +1 -0
  198. data/app/assets/images/payment_icons/upi.svg +1 -0
  199. data/app/assets/images/payment_icons/usbank.svg +1 -0
  200. data/app/assets/images/payment_icons/usdc.svg +1 -0
  201. data/app/assets/images/payment_icons/usdt.svg +1 -0
  202. data/app/assets/images/payment_icons/venmo.svg +1 -0
  203. data/app/assets/images/payment_icons/vipps.svg +1 -0
  204. data/app/assets/images/payment_icons/visa.svg +1 -0
  205. data/app/assets/images/payment_icons/volksbank.svg +1 -0
  206. data/app/assets/images/payment_icons/waavepaybybank.svg +1 -0
  207. data/app/assets/images/payment_icons/walley.svg +1 -0
  208. data/app/assets/images/payment_icons/wbtc.svg +1 -0
  209. data/app/assets/images/payment_icons/wechatpay.svg +1 -0
  210. data/app/assets/images/payment_icons/whishcheckout.svg +1 -0
  211. data/app/assets/images/payment_icons/wingbank.svg +1 -0
  212. data/app/assets/images/payment_icons/xrp.svg +1 -0
  213. data/app/assets/images/payment_icons/zip.svg +1 -0
  214. data/app/finders/spree/posts/find.rb +137 -0
  215. data/app/helpers/spree/addresses_helper.rb +9 -3
  216. data/app/helpers/spree/base_helper.rb +8 -4
  217. data/app/helpers/spree/currency_helper.rb +21 -6
  218. data/app/jobs/spree/images/save_from_url_job.rb +70 -0
  219. data/app/jobs/spree/imports/create_rows_job.rb +72 -0
  220. data/app/jobs/spree/imports/process_rows_job.rb +19 -0
  221. data/app/models/concerns/spree/adjustment_source.rb +3 -3
  222. data/app/models/concerns/spree/admin_user_methods.rb +52 -0
  223. data/app/models/concerns/spree/display_on.rb +7 -1
  224. data/app/models/concerns/spree/has_image_alt_text.rb +18 -0
  225. data/app/models/concerns/spree/has_one_link.rb +1 -1
  226. data/app/models/concerns/spree/has_page_links.rb +1 -1
  227. data/app/models/concerns/spree/linkable.rb +9 -0
  228. data/app/models/concerns/spree/metadata.rb +2 -0
  229. data/app/models/concerns/spree/metafields.rb +94 -0
  230. data/app/models/concerns/spree/named_type.rb +1 -1
  231. data/app/models/concerns/spree/user_methods.rb +26 -9
  232. data/app/models/concerns/spree/user_payment_source.rb +1 -1
  233. data/app/models/concerns/spree/user_roles.rb +3 -2
  234. data/app/models/spree/ability.rb +4 -0
  235. data/app/models/spree/address.rb +6 -2
  236. data/app/models/spree/adjustable/adjuster/tax.rb +2 -2
  237. data/app/models/spree/adjustable/adjustments_updater.rb +26 -3
  238. data/app/models/spree/adjustment.rb +4 -1
  239. data/app/models/spree/asset.rb +16 -0
  240. data/app/models/spree/base.rb +1 -1
  241. data/app/models/spree/calculator.rb +1 -1
  242. data/app/models/spree/credit_card.rb +1 -0
  243. data/app/models/spree/current.rb +5 -1
  244. data/app/models/spree/custom_domain.rb +5 -0
  245. data/app/models/spree/customer_return.rb +1 -0
  246. data/app/models/spree/export.rb +39 -2
  247. data/app/models/spree/exports/customers.rb +17 -0
  248. data/app/models/spree/exports/gift_cards.rb +13 -0
  249. data/app/models/spree/exports/newsletter_subscribers.rb +13 -0
  250. data/app/models/spree/exports/orders.rb +6 -4
  251. data/app/models/spree/exports/products.rb +9 -3
  252. data/app/models/spree/gateway/bogus.rb +4 -0
  253. data/app/models/spree/gateway/custom_payment_source_method.rb +4 -0
  254. data/app/models/spree/gift_card.rb +9 -1
  255. data/app/models/spree/gift_card_batch.rb +0 -1
  256. data/app/models/spree/import.rb +279 -0
  257. data/app/models/spree/import_mapping.rb +46 -0
  258. data/app/models/spree/import_row.rb +108 -0
  259. data/app/models/spree/import_schema.rb +25 -0
  260. data/app/models/spree/import_schemas/products.rb +45 -0
  261. data/app/models/spree/imports/products.rb +9 -0
  262. data/app/models/spree/invitation.rb +1 -1
  263. data/app/models/spree/legacy_user.rb +0 -1
  264. data/app/models/spree/line_item.rb +3 -8
  265. data/app/models/spree/metafield.rb +53 -0
  266. data/app/models/spree/metafield_definition.rb +91 -0
  267. data/app/models/spree/metafields/boolean.rb +15 -0
  268. data/app/models/spree/metafields/json.rb +27 -0
  269. data/app/models/spree/metafields/long_text.rb +7 -0
  270. data/app/models/spree/metafields/number.rb +15 -0
  271. data/app/models/spree/metafields/rich_text.rb +18 -0
  272. data/app/models/spree/metafields/short_text.rb +7 -0
  273. data/app/models/spree/newsletter_subscriber/emails.rb +12 -0
  274. data/app/models/spree/newsletter_subscriber.rb +64 -0
  275. data/app/models/spree/option_type.rb +2 -0
  276. data/app/models/spree/option_value.rb +1 -0
  277. data/app/models/spree/order/checkout.rb +7 -0
  278. data/app/models/spree/order/payments.rb +1 -1
  279. data/app/models/spree/order.rb +14 -11
  280. data/app/models/spree/order_merger.rb +2 -4
  281. data/app/models/spree/order_promotion.rb +3 -0
  282. data/app/models/spree/order_updater.rb +2 -2
  283. data/app/models/spree/page.rb +5 -1
  284. data/app/models/spree/page_block.rb +4 -0
  285. data/app/models/spree/page_blocks/image.rb +3 -0
  286. data/app/models/spree/page_blocks/metafields.rb +18 -0
  287. data/app/models/spree/page_blocks/products/brand.rb +15 -0
  288. data/app/models/spree/page_blocks/products/buy_buttons.rb +5 -1
  289. data/app/models/spree/page_blocks/products/description.rb +18 -0
  290. data/app/models/spree/page_blocks/products/price.rb +1 -1
  291. data/app/models/spree/page_blocks/products/quantity_selector.rb +6 -2
  292. data/app/models/spree/page_blocks/products/title.rb +5 -1
  293. data/app/models/spree/page_blocks/products/variant_picker.rb +1 -1
  294. data/app/models/spree/page_section.rb +2 -2
  295. data/app/models/spree/page_sections/breadcrumbs.rb +12 -0
  296. data/app/models/spree/page_sections/footer.rb +20 -13
  297. data/app/models/spree/page_sections/image_banner.rb +6 -1
  298. data/app/models/spree/page_sections/image_with_text.rb +5 -0
  299. data/app/models/spree/page_sections/newsletter.rb +7 -0
  300. data/app/models/spree/page_sections/product_details.rb +38 -1
  301. data/app/models/spree/pages/account.rb +4 -0
  302. data/app/models/spree/pages/cart.rb +10 -0
  303. data/app/models/spree/pages/checkout.rb +6 -0
  304. data/app/models/spree/pages/custom.rb +4 -0
  305. data/app/models/spree/pages/homepage.rb +4 -0
  306. data/app/models/spree/pages/login.rb +4 -0
  307. data/app/models/spree/pages/password.rb +2 -0
  308. data/app/models/spree/pages/post_list.rb +5 -1
  309. data/app/models/spree/pages/product_details.rb +1 -0
  310. data/app/models/spree/pages/search_results.rb +1 -1
  311. data/app/models/spree/pages/shop_all.rb +5 -1
  312. data/app/models/spree/pages/wishlist.rb +4 -0
  313. data/app/models/spree/payment.rb +1 -0
  314. data/app/models/spree/payment_method.rb +8 -5
  315. data/app/models/spree/payment_source.rb +1 -0
  316. data/app/models/spree/policy.rb +70 -0
  317. data/app/models/spree/post.rb +4 -2
  318. data/app/models/spree/post_category.rb +1 -0
  319. data/app/models/spree/product.rb +16 -9
  320. data/app/models/spree/promotion/actions/free_shipping.rb +3 -3
  321. data/app/models/spree/promotion.rb +24 -8
  322. data/app/models/spree/promotion_action.rb +1 -1
  323. data/app/models/spree/promotion_handler/cart.rb +1 -1
  324. data/app/models/spree/promotion_handler/coupon.rb +1 -1
  325. data/app/models/spree/promotion_rule.rb +1 -1
  326. data/app/models/spree/property.rb +18 -0
  327. data/app/models/spree/refund.rb +2 -1
  328. data/app/models/spree/role_user.rb +1 -1
  329. data/app/models/spree/shipment.rb +1 -0
  330. data/app/models/spree/shipping_method.rb +1 -0
  331. data/app/models/spree/stock_item.rb +1 -0
  332. data/app/models/spree/stock_transfer.rb +1 -0
  333. data/app/models/spree/store.rb +45 -3
  334. data/app/models/spree/store_credit.rb +2 -1
  335. data/app/models/spree/tax_category.rb +1 -1
  336. data/app/models/spree/tax_rate.rb +18 -3
  337. data/app/models/spree/taxon.rb +12 -2
  338. data/app/models/spree/taxonomy.rb +11 -0
  339. data/app/models/spree/theme.rb +1 -1
  340. data/app/models/spree/variant.rb +17 -0
  341. data/app/presenters/spree/csv/customer_presenter.rb +59 -0
  342. data/app/presenters/spree/csv/gift_card_presenter.rb +49 -0
  343. data/app/presenters/spree/csv/metafields_helper.rb +17 -0
  344. data/app/presenters/spree/csv/newsletter_subscriber_presenter.rb +39 -0
  345. data/app/presenters/spree/csv/order_line_item_presenter.rb +12 -5
  346. data/app/presenters/spree/csv/product_variant_presenter.rb +9 -5
  347. data/app/services/spree/addresses/update.rb +8 -1
  348. data/app/services/spree/cart/recalculate.rb +6 -4
  349. data/app/services/spree/cart/remove_line_item.rb +1 -2
  350. data/app/services/spree/imports/row_processors/base.rb +19 -0
  351. data/app/services/spree/imports/row_processors/product_variant.rb +228 -0
  352. data/app/services/spree/line_items/destroy.rb +1 -1
  353. data/app/services/spree/newsletter/subscribe.rb +43 -0
  354. data/app/services/spree/newsletter/verify.rb +30 -0
  355. data/app/services/spree/orders/create_user_account.rb +5 -1
  356. data/app/services/spree/products/prepare_nested_attributes.rb +44 -0
  357. data/app/sorters/spree/posts/sort.rb +40 -0
  358. data/app/{services → validators}/spree/addresses/phone_validator.rb +1 -1
  359. data/app/views/spree/shared/_payment.html.erb +11 -9
  360. data/config/locales/en.yml +56 -2
  361. data/db/migrate/20250605131334_add_missing_fields_to_users.rb +23 -13
  362. data/db/migrate/20250728095629_create_spree_metafields.rb +27 -0
  363. data/db/migrate/20250730102644_add_missing_unique_indexes_to_spree_option_types_and_values.rb +40 -0
  364. data/db/migrate/20250730154601_add_unique_index_on_spree_properties_name.rb +24 -0
  365. data/db/migrate/20250811112056_create_spree_policies.rb +22 -0
  366. data/db/migrate/20250821211705_fix_unique_index_on_spree_order_promotions.rb +20 -0
  367. data/db/migrate/20250825175217_add_missing_page_builder_indexes.rb +7 -0
  368. data/db/migrate/20250826093602_create_spree_newsletter_subscribers.rb +12 -0
  369. data/db/migrate/20250902143122_fix_policies_store_association.rb +18 -0
  370. data/db/migrate/20250911205659_add_missing_index_on_spree_products_promotionable.rb +5 -0
  371. data/db/migrate/20250913130044_add_page_links_counter_cache_to_spree_stores.rb +10 -0
  372. data/db/migrate/20250914101955_add_missing_indexes_on_spree_adjustments.rb +6 -0
  373. data/db/migrate/20250915093930_add_metadata_to_spree_newsletter_subscribers.rb +20 -0
  374. data/db/migrate/20250923141845_create_spree_imports.rb +47 -0
  375. data/lib/generators/spree/cursor_rules/cursor_rules_generator.rb +19 -0
  376. data/lib/generators/spree/cursor_rules/templates/spree_rules.mdc +387 -0
  377. data/lib/generators/spree/dummy/dummy_generator.rb +0 -1
  378. data/lib/generators/spree/install/templates/config/initializers/spree.rb +5 -0
  379. data/lib/spree/core/configuration.rb +1 -0
  380. data/lib/spree/core/dependencies.rb +3 -0
  381. data/lib/spree/core/engine.rb +57 -2
  382. data/lib/spree/core/version.rb +1 -1
  383. data/lib/spree/core.rb +3 -1
  384. data/lib/spree/permitted_attributes.rb +18 -3
  385. data/lib/spree/testing_support/capybara_config.rb +9 -3
  386. data/lib/spree/testing_support/common_rake.rb +5 -5
  387. data/lib/spree/testing_support/factories/export_factory.rb +5 -17
  388. data/lib/spree/testing_support/factories/import_factory.rb +20 -0
  389. data/lib/spree/testing_support/factories/import_mapping_factory.rb +7 -0
  390. data/lib/spree/testing_support/factories/import_row_factory.rb +7 -0
  391. data/lib/spree/testing_support/factories/metafield_definition_factory.rb +72 -0
  392. data/lib/spree/testing_support/factories/metafield_factory.rb +68 -0
  393. data/lib/spree/testing_support/factories/newsletter_subscriber_factory.rb +18 -0
  394. data/lib/spree/testing_support/factories/policy_factory.rb +8 -0
  395. data/lib/spree/testing_support/factories/post_factory.rb +8 -0
  396. data/lib/spree/testing_support/store.rb +11 -0
  397. data/lib/tasks/core.rake +130 -3
  398. metadata +280 -7
  399. data/app/models/action_text/rich_text_decorator.rb +0 -11
  400. data/app/presenters/spree/csv/product_presenter.rb +0 -63
@@ -1,24 +1,8 @@
1
- # == Schema Information
2
- #
3
- # Table name: spree_exports
4
- #
5
- # id :uuid not null, primary key
6
- # format :integer not null
7
- # number :string(32) not null
8
- # search_params :jsonb
9
- # type :string not null
10
- # created_at :datetime not null
11
- # updated_at :datetime not null
12
- # project_id :uuid not null
13
- # store_id :uuid not null
14
- # user_id :uuid
15
- # vendor_id :uuid
16
- #
17
1
  FactoryBot.define do
18
2
  factory :export, class: 'Spree::Export' do
19
3
  store { create(:store) }
20
4
  user { create(:admin_user) }
21
- type { 'Spree::Export::Products' }
5
+ type { 'Spree::Exports::Products' }
22
6
  format { 'csv' }
23
7
 
24
8
  factory :product_export, class: 'Spree::Exports::Products', parent: :export do
@@ -28,5 +12,9 @@ FactoryBot.define do
28
12
  factory :order_export, class: 'Spree::Exports::Orders', parent: :export do
29
13
  type { 'Spree::Exports::Orders' }
30
14
  end
15
+
16
+ factory :customer_export, class: 'Spree::Exports::Customers', parent: :export do
17
+ type { 'Spree::Exports::Customers' }
18
+ end
31
19
  end
32
20
  end
@@ -0,0 +1,20 @@
1
+ FactoryBot.define do
2
+ factory :import, class: 'Spree::Import' do
3
+ owner { Spree::Store.default || create(:store) }
4
+ user { create(:admin_user) }
5
+ type { 'Spree::Imports::Products' }
6
+
7
+ factory :product_import, class: 'Spree::Imports::Products', parent: :import do
8
+ type { 'Spree::Imports::Products' }
9
+ # attachment { Rack::Test::UploadedFile.new(Spree::Core::Engine.root.join('spec', 'fixtures', 'files', 'products_import.csv'), 'text/csv') }
10
+
11
+ after(:create) do |import|
12
+ import.attachment.attach(
13
+ io: File.open(Spree::Core::Engine.root.join('spec', 'fixtures', 'files', 'products_import.csv')),
14
+ filename: 'products_import.csv',
15
+ content_type: 'text/csv'
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ FactoryBot.define do
2
+ factory :import_mapping, class: 'Spree::ImportMapping' do
3
+ import { create(:product_import) }
4
+ schema_field { 'name' }
5
+ file_column { 'name' }
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ FactoryBot.define do
2
+ factory :import_row, class: 'Spree::ImportRow' do
3
+ import { create(:product_import) }
4
+ data { { 'slug' => 'test-product', 'name' => 'Test Product', 'price' => '10.00' }.to_json }
5
+ row_number { import.rows_count + 1 }
6
+ end
7
+ end
@@ -0,0 +1,72 @@
1
+ FactoryBot.define do
2
+ factory :metafield_definition, class: 'Spree::MetafieldDefinition' do
3
+ namespace { 'custom' }
4
+ sequence(:key) { |n| "custom_field_#{n}" }
5
+ name { 'Custom Field' }
6
+ metafield_type { 'Spree::Metafields::ShortText' }
7
+ resource_type { 'Spree::Product' }
8
+ display_on { 'both' }
9
+
10
+ trait :front_end_only do
11
+ display_on { 'front_end' }
12
+ end
13
+
14
+ trait :back_end_only do
15
+ display_on { 'back_end' }
16
+ end
17
+
18
+ trait :short_text_field do
19
+ metafield_type { 'Spree::Metafields::ShortText' }
20
+ key { 'title' }
21
+ name { 'Title' }
22
+ end
23
+
24
+ trait :long_text_field do
25
+ metafield_type { 'Spree::Metafields::LongText' }
26
+ key { 'description' }
27
+ name { 'Description' }
28
+ end
29
+
30
+ trait :rich_text_field do
31
+ metafield_type { 'Spree::Metafields::RichText' }
32
+ key { 'content' }
33
+ name { 'Content' }
34
+ end
35
+
36
+ trait :number_field do
37
+ metafield_type { 'Spree::Metafields::Number' }
38
+ key { 'priority' }
39
+ name { 'Priority' }
40
+ end
41
+
42
+ trait :boolean_field do
43
+ metafield_type { 'Spree::Metafields::Boolean' }
44
+ key { 'featured' }
45
+ name { 'Featured' }
46
+ end
47
+
48
+ trait :json_field do
49
+ metafield_type { 'Spree::Metafields::Json' }
50
+ key { 'metadata' }
51
+ name { 'Metadata' }
52
+ end
53
+
54
+ trait :for_variant do
55
+ resource_type { 'Spree::Variant' }
56
+ key { 'variant_custom' }
57
+ name { 'Variant Custom Field' }
58
+ end
59
+
60
+ trait :for_order do
61
+ resource_type { 'Spree::Order' }
62
+ key { 'order_notes' }
63
+ name { 'Order Notes' }
64
+ end
65
+
66
+ trait :for_user do
67
+ resource_type { Spree.user_class.name }
68
+ key { 'user_preference' }
69
+ name { 'User Preference' }
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,68 @@
1
+ FactoryBot.define do
2
+ factory :metafield, class: 'Spree::Metafield' do
3
+ value { 'test_value' }
4
+ type { 'Spree::Metafields::ShortText' }
5
+
6
+ association :resource, factory: :product
7
+ association :metafield_definition
8
+
9
+ trait :front_end_only do
10
+ association :metafield_definition, :front_end_only
11
+ end
12
+
13
+ trait :back_end_only do
14
+ association :metafield_definition, :back_end_only
15
+ end
16
+
17
+ trait :short_text do
18
+ type { 'Spree::Metafields::ShortText' }
19
+ association :metafield_definition, :short_text_field
20
+ value { 'Short text value' }
21
+ end
22
+
23
+ trait :long_text do
24
+ type { 'Spree::Metafields::LongText' }
25
+ association :metafield_definition, :long_text_field
26
+ value { 'This is a longer text value with more detailed information.' }
27
+ end
28
+
29
+ trait :number do
30
+ type { 'Spree::Metafields::Number' }
31
+ association :metafield_definition, :number_field
32
+ value { 42 }
33
+ end
34
+
35
+ trait :rich_text do
36
+ type { 'Spree::Metafields::RichText' }
37
+ association :metafield_definition, :rich_text_field
38
+ value { '<p>Rich text with <strong>formatting</strong></p>' }
39
+ end
40
+
41
+ trait :boolean do
42
+ type { 'Spree::Metafields::Boolean' }
43
+ association :metafield_definition, :boolean_field
44
+ value { true }
45
+ end
46
+
47
+ trait :json do
48
+ type { 'Spree::Metafields::Json' }
49
+ association :metafield_definition, :json_field
50
+ value { '{"key": "value"}' }
51
+ end
52
+
53
+ trait :for_variant do
54
+ association :resource, factory: :variant
55
+ association :metafield_definition, :for_variant
56
+ end
57
+
58
+ trait :for_order do
59
+ association :resource, factory: :order
60
+ association :metafield_definition, :for_order
61
+ end
62
+
63
+ trait :for_user do
64
+ association :resource, factory: :user
65
+ association :metafield_definition, :for_user
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,18 @@
1
+ FactoryBot.define do
2
+ factory :newsletter_subscriber, class: Spree::NewsletterSubscriber do
3
+ email { FFaker::Internet.unique.email }
4
+ verified_at { nil }
5
+
6
+ trait :with_user do
7
+ association :user, factory: :user
8
+ end
9
+
10
+ trait :verified do
11
+ verified_at { Time.current }
12
+ end
13
+
14
+ trait :unverified do
15
+ verified_at { nil }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,8 @@
1
+ FactoryBot.define do
2
+ factory :policy, class: 'Spree::Policy' do
3
+ owner { Spree::Store.default }
4
+ slug { 'my-policy' }
5
+ name { 'My Policy' }
6
+ body { 'This is the my policy' }
7
+ end
8
+ end
@@ -10,5 +10,13 @@ FactoryBot.define do
10
10
  trait :with_image do
11
11
  image { Rack::Test::UploadedFile.new(Spree::Core::Engine.root.join('spec/fixtures/thinking-cat.jpg'), 'image/jpeg') }
12
12
  end
13
+
14
+ trait :published do
15
+ published_at { Time.current }
16
+ end
17
+
18
+ trait :unpublished do
19
+ published_at { nil }
20
+ end
13
21
  end
14
22
  end
@@ -1,5 +1,16 @@
1
1
  # setup default store, to be always present
2
2
  RSpec.configure do |config|
3
+ config.before(:suite) do
4
+ if defined?(ActiveSupport::SafeBuffer)
5
+ ActiveSupport::SafeBuffer.class_eval do
6
+ # Make Psych serialize SafeBuffer as a plain string
7
+ def encode_with(coder)
8
+ coder.represent_scalar(nil, to_s)
9
+ end
10
+ end
11
+ end
12
+ end
13
+
3
14
  config.before(:all) do
4
15
  unless self.class.metadata[:without_global_store]
5
16
  @default_country = Spree::Country.find_by(iso: 'US') || FactoryBot.create(:country_us)
data/lib/tasks/core.rake CHANGED
@@ -186,9 +186,118 @@ use rake db:load_file[/absolute/path/to/sample/filename.rb]}
186
186
  end
187
187
 
188
188
  task migrate_admin_users_to_role_users: :environment do |_t, _args|
189
- Spree.admin_user_class.all.each do |admin_user|
190
- Spree::Store.all.each do |store|
191
- store.add_user(admin_user)
189
+ default_store = Spree::Store.default
190
+ Spree::RoleUser.where(resource: nil).each do |role_user|
191
+ role_user.update_columns(resource_type: default_store.class.name, resource_id: default_store.id)
192
+ end
193
+ end
194
+
195
+ desc 'Migrate policies to store policies'
196
+ task migrate_policies: :environment do |_t, _args|
197
+ # Helper to consistently derive policy name
198
+ derive_policy_name = lambda do |name_str|
199
+ name_str.to_s.gsub(/customer_/, '').gsub(/_policy$/, '')
200
+ end
201
+
202
+ # Check if migration has already been run
203
+ if Spree::Policy.any?
204
+ puts "Policies already exist. Skipping migration to prevent duplicates."
205
+ exit
206
+ end
207
+
208
+ Spree::Store.all.each do |store|
209
+ %w[customer_terms_of_service customer_privacy_policy customer_returns_policy customer_shipping_policy].each do |policy_slug|
210
+ policy = store.send(policy_slug)
211
+ next unless policy.present?
212
+
213
+ store.policies.create(
214
+ name: Spree.t(derive_policy_name.call(policy_slug)),
215
+ body: policy.body
216
+ )
217
+
218
+ puts "Migrated #{policy_slug} to store #{store.id}"
219
+ end
220
+ end
221
+
222
+ Spree::PageLink.where(linkable_type: 'ActionText::RichText').each do |page_link|
223
+ # Check if this page link is attached to ActionText content
224
+ # Find the ActionText record
225
+ action_text = ActionText::RichText.find_by(id: page_link.linkable_id)
226
+ next unless action_text
227
+
228
+ # Check if the ActionText belongs to a store policy
229
+ if action_text.record_type == 'Spree::Store' && action_text.name.to_s.include?('policy')
230
+ # Find the corresponding policy in the new policies system
231
+ store = action_text.record
232
+ policy_name = derive_policy_name.call(action_text.name)
233
+
234
+ policy = store.policies.find_by(name: Spree.t(policy_name))
235
+
236
+ if policy
237
+ # Update the page link to point to the policy instead
238
+ page_link.update!(
239
+ linked_resource_type: 'Spree::Policy',
240
+ linked_resource_id: policy.id
241
+ )
242
+
243
+ puts "Migrated #{policy_name} to store #{store.id}"
244
+ end
245
+ end
246
+ end
247
+ end
248
+
249
+ desc 'Migrate product properties to metafields'
250
+ task migrate_product_properties_to_metafields: :environment do |_t, _args|
251
+ Spree::Property.find_each do |property|
252
+ metafield_definition = Spree::MetafieldDefinition.find_or_initialize_by(
253
+ namespace: 'properties',
254
+ key: property.name,
255
+ resource_type: 'Spree::Product'
256
+ )
257
+ metafield_definition.assign_attributes(
258
+ metafield_type: property.kind_to_metafield_type,
259
+ display_on: property.display_on
260
+ )
261
+ metafield_definition.save!
262
+
263
+ property.product_properties.includes(:product).find_each do |product_property|
264
+ product_property.product.set_metafield("properties.#{property.name}", product_property.value)
265
+ puts "Migrated #{property.name} to product #{product_property.product.id}"
266
+ end
267
+ end
268
+ end
269
+
270
+ desc 'Migrate product details sections to PDP 2.0 with blocks and metafields'
271
+ task migrate_product_details_pages: :environment do |_t, _args|
272
+ Spree::PageSections::ProductDetails.find_each do |section|
273
+ next if section.blocks.any?
274
+
275
+ if defined?(SpreeMultiTenant)
276
+ SpreeMultiTenant.with_tenant(section.tenant) do
277
+ section.send(:create_blocks)
278
+ end
279
+ else
280
+ section.send(:create_blocks)
281
+ end
282
+ end
283
+
284
+ Spree::Pages::ProductDetails.find_each do |page|
285
+ next if page.sections.exists?(type: 'Spree::PageSections::Breadcrumbs')
286
+
287
+ block = proc do
288
+ breadcrumbs = page.sections.create!(type: 'Spree::PageSections::Breadcrumbs')
289
+ breadcrumbs.move_to_top
290
+
291
+ page_details = page.sections.find_by(type: 'Spree::PageSections::ProductDetails')
292
+ if page_details.present?
293
+ page_details.update!(preferred_top_padding: 0, preferred_top_border_width: 0)
294
+ end
295
+ end
296
+
297
+ if defined?(SpreeMultiTenant)
298
+ SpreeMultiTenant.with_tenant(page.tenant, &block)
299
+ else
300
+ block.call
192
301
  end
193
302
  end
194
303
  end
@@ -217,4 +326,22 @@ namespace :core do
217
326
  puts '... done'
218
327
  puts "... migrated #{pluralize(total, 'record')}"
219
328
  end
329
+
330
+ desc 'Migrate newsletter subscribers'
331
+ task migrate_newsletter_subscribers: :environment do |_t, _args|
332
+ Spree.user_class.where(accepts_email_marketing: true).in_batches(of: 500) do |user_batch|
333
+ subscriber_attributes = user_batch.pluck(:id, :email, :updated_at).map do |id, email, updated_at|
334
+ {
335
+ email: Spree::NewsletterSubscriber.new(email: email).email, # normalized email
336
+ user_id: id,
337
+ verified_at: updated_at,
338
+ verification_token: nil,
339
+ updated_at: DateTime.current,
340
+ created_at: DateTime.current
341
+ }
342
+ end
343
+
344
+ Spree::NewsletterSubscriber.insert_all(subscriber_attributes.uniq { |attrs| attrs[:email] })
345
+ end
346
+ end
220
347
  end